{"action":"created","comment":{"url":"https://api.github.com/repos/lsst/qserv/pulls/comments/45247711","id":45247711,"diff_hunk":"@@ -0,0 +1,315 @@\n+// -*- LSST-C++ -*-\n+/*\n+ * LSST Data Management System\n+ * Copyright 2014-2015 LSST Corporation.\n+ *\n+ * This product includes software developed by the\n+ * LSST Project (http://www.lsst.org/).\n+ *\n+ * This program is free software: you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License as published by\n+ * the Free Software Foundation, either version 3 of the License, or\n+ * (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the LSST License Statement and\n+ * the GNU General Public License along with this program.  If not,\n+ * see <http://www.lsstcorp.org/LegalNotices/>.\n+ */\n+\n+#ifndef LSST_QSERV_SSCAN_DIRECTOR_H\n+#define LSST_QSERV_SSCAN_DIRECTOR_H\n+\n+// System headers\n+#include <memory>\n+#include <string>\n+#include <vector>\n+\n+namespace lsst {\n+namespace qserv {\n+namespace shrscan {\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Describe a required table for a shared scan query.\n+//-----------------------------------------------------------------------------\n+\n+class TableInfo\n+{\n+public:\n+\n+std::string tableName;    //< Name of the table\n+bool        lockIndex;    //< If true, the table's index is locked, if any.\n+bool        lockData;     //< If true, the table's data  is locked\n+\n+//-----------------------------------------------------------------------------\n+//! Constructor\n+//!\n+//! @param  tabName   is the name of the table.\n+//! @param  lkIndex   whether or not to lock the table's index\n+//! @param  lkData    whether or not to lock the table's data\n+//-----------------------------------------------------------------------------\n+\n+            TableInfo(const char *tabName=\"\", bool lkIndex=true, bool lkData=true)\n+                     : tableName(tabName), lockIndex(lkIndex), lockData(lkData)\n+                     {}\n+\n+//-----------------------------------------------------------------------------\n+//! Destructor\n+//-----------------------------------------------------------------------------\n+\n+           ~TableInfo() {}\n+};\n+\n+//-----------------------------------------------------------------------------\n+//! @brief The Query pure abstract class describes a shared scan query.\n+//-----------------------------------------------------------------------------\n+\n+class Query\n+{\n+public:\n+\n+//-----------------------------------------------------------------------------\n+//! @brief The callback method to indicate a query has finished its run.\n+//!\n+//! The endQuery() method is called when the query completes or is canceled.\n+//! This method is always called on a separate thread.\n+//!\n+//! @param  badChunks is a smart pointer to a vector of unprocessed chunks. This\n+//!                   includes the chunk that was being processed if Run()\n+//!                   returned false. You must take ownership of the shared\n+//!                   pointer if you want to persist the vector upon return.\n+//! @return canceled  When true, the query was cancelled and badChunks will be a\n+//!                   zero length vector. Otherwise, the query completed and\n+//!                   badChunks does hold the unprocessed chunk numbers.\n+//-----------------------------------------------------------------------------\n+\n+virtual void endQuery(std::shared_ptr<std::vector<int>> const& badChunks,\n+                      bool canceled) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief The callack method to run a query on a chunk.\n+//!\n+//! The runQuery() method is invoked by the shared scan director to initiate the\n+//! start of a query on a particular chunk.\n+//!\n+//! @param  chunkNum  is the number of the chunk to be processed.\n+//!\n+//! @return false     the query should be cancelled and endQuery() called.\n+//! @return true      continue to the next chunk, if any.\n+//-----------------------------------------------------------------------------\n+\n+virtual bool runQuery(int chunkNum) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! The following vector should be used to add additional tables that may be\n+//! needed by this particular query prior to call Director::addQuery(). These\n+//! are in addition to the tables that the director was created with.\n+//-----------------------------------------------------------------------------\n+\n+std::vector<TableInfo> tables; //< Additional tables needed by this query\n+\n+//-----------------------------------------------------------------------------\n+//! Constructor & Destructor\n+//-----------------------------------------------------------------------------\n+\n+             Query() {}\n+virtual     ~Query() {}\n+};\n+\n+//-----------------------------------------------------------------------------\n+//! @brief The shared scan director.\n+//!\n+//! The Director is an abstract class the defines the interface to the\n+//! shared scan director that accepts, schedules, and dispatches queries.\n+//-----------------------------------------------------------------------------\n+\n+class Director\n+{\n+public:\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Add a query to the shared scan queue.\n+//!\n+//! @param  query - Pointer to a Query object that describes the query.\n+//-----------------------------------------------------------------------------\n+\n+virtual void  addQuery(std::shared_ptr<Query> const& query) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Cancel a shared scan query.\n+//!\n+//! When a query is cancelled, the Query object's endQuery() method is called.\n+//! If the query is executing its runQuery() method, cancellation occurs upon\n+//! return.\n+//!\n+//! @param  query   - Pointer to a Query object that describes the query.\n+//! @param  wait    - When true, does not return until the query has been\n+//!                   actually cancelled (i.e. endQuery() method called).\n+//!\n+//! @return false: The query was not found.\n+//! @return true:  The query was cancelled or was scheduled to be cancelled.\n+//-----------------------------------------------------------------------------\n+\n+virtual bool  cancelQuery(Query const* query, bool wait=false) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Cancel all shared scan queries.\n+//!\n+//! @param  wait    - When true, does not return until all queries have been\n+//!                   actually cancelled (i.e. endQuery() method called).\n+//!\n+//! This method effectively calls cancelQuery() on each query.\n+//-----------------------------------------------------------------------------\n+\n+virtual void  cancelAll(bool wait=false) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Obtain statistics about this shared scan director.\n+//!\n+//! @param  stats   - Where information is to be returned (see struct below).\n+//!\n+//! @return The number of queries actually running.\n+//-----------------------------------------------------------------------------\n+\n+struct Statistics {\n+    unsigned long long bytesLockMax;//< Maximum number of bytes to lock\n+    unsigned long long bytesLocked; //< Actual  number of bytes locked in memory\n+    unsigned long long msRunTotal;  //< Total milliseconds spent running\n+    unsigned long long msIdleTotal; //< Total milliseconds spent idling\n+    unsigned int       numChunks;   //< The number of chunks being handled\n+    unsigned int       maxCanRun;   //< Maximum number of parallel queries\n+    unsigned int       numQueued;   //< Number waiting to run\n+    unsigned int       numRunning;  //< Number actually running\n+    unsigned int       numSuspend;  //< Number suspended\n+    unsigned int       numErrors;   //< Number of queries that had errors\n+    unsigned int       numCancelled;//< Number of queries that were cancelled\n+};\n+\n+virtual void  getStatistics(Statistics &stats) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Obtain query status.\n+//!\n+//! @param  query   - Pointer to a Query object that describes the query.\n+//! @param  info    - Where information is to be returned (see struct below).\n+//!\n+//! @return false: The query was not found, status struct not touched.\n+//! @return true:  The query information returned in status.\n+//-----------------------------------------------------------------------------\n+\n+struct Status {\n+    unsigned int   secInQ;    //< Seconds      waiting to run (wall clock)\n+    unsigned int   msRunning; //< Milliseconds running so far (wall clock)\n+    unsigned int   msIdling;  //< Milliseconds in idle state  (wall clock)\n+    unsigned short pctChunks; //< Percentage of chunks processed times 100\n+    bool           isRunning; //< When true is actually running\n+    bool           isSuspend; //< When true is currently suspended\n+};\n+\n+virtual bool  getStatus(Query const* query, Status &status) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Initialize for processing.\n+//!\n+//! The init() method should be called after construction of the director and\n+//! before calling any of it's method. Initialization involves locking the base\n+//! tables in memory which may be a lengthy processes.\n+//!\n+//! @param  dbPath     - filesystem path where database tables reside.\n+//! @param  baseTables - The tables that need to remain locked in memory.\n+//! @param  chunkList  - The list of chunk numbers to be processed.\n+//!\n+//! @return false: Initialization failed (e.g. not all chunks were found).\n+//! @return true:  Initialization succeeded.\n+//-----------------------------------------------------------------------------\n+\n+virtual bool  init(const std::string dbPath, TableInfo const& baseTables,\n+                   std::shared_ptr<std::vector<int>> const& chunkList);\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Resume a possibly suspended shared scan query.\n+//!\n+//! When a query is resumed it becomes eligible to run when sufficient\n+//! resources become available.\n+//!\n+//! @param  query - Pointer to a Query object that describes the query.\n+//!\n+//! @return false: The query was not found.\n+//! @return true:  The query was resumed.\n+//-----------------------------------------------------------------------------\n+\n+virtual bool  resumeQuery(Query const* query) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Resume all suspended shared scan queries.\n+//!\n+//! This method effectively calls resumeQuery() on each suspended query.\n+//-----------------------------------------------------------------------------\n+\n+virtual void  resumeAll() = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Set the maximum amount of memory that may be locked.\n+//!\n+//! The default maximum amount of memory that may be locked is equal to largest\n+//! amount of memory needed to lock a set of table chunks passed to init().\n+//!\n+//! @param  bytes  - The maximum number of bytes that may be locked.\n+//-----------------------------------------------------------------------------\n+\n+virtual void  setMaxMemory(unsigned long long bytes) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Set the maximum number of queries that be run in parallel.\n+//!\n+//! The default number of parallel queries is 7.\n+//!\n+//! @param  maxNum - The maximum number of queries to run in parallel.\n+//-----------------------------------------------------------------------------\n+\n+virtual void  SetMaxQueries(int qnum) = 0;\n+\n+//-----------------------------------------------------------------------------\n+//! @brief Suspend a shared scan query.\n+//!\n+//! When a running query is suspended, it is placed in the eligible to run\n+//! queue in FIFO order. If the query is executing its runQuery() method, the\n+//! suspension occurs upon return.\n+//!\n+//! @param  query   - Pointer to the Query object that describes the query.\n+//! @param  unlock  - When true, any additional tables required by the query\n+//!                   that were locked are unlocked. Otherwise, the tables\n+//!                   remain locked which may prevent new queries to run.\n+//!\n+//! @return false: The query was not found.\n+//! @return true:  The query was suspended or scheduled to be suspended.","path":"core/modules/shrscan/Director.h","position":289,"original_position":289,"commit_id":"0a78e1cb63a73a911413067652a177fe0f4268eb","original_commit_id":"0a78e1cb63a73a911413067652a177fe0f4268eb","user":{"login":"andy-slac","id":4266950,"avatar_url":"https://avatars.githubusercontent.com/u/4266950?v=3","gravatar_id":"","url":"https://api.github.com/users/andy-slac","html_url":"https://github.com/andy-slac","followers_url":"https://api.github.com/users/andy-slac/followers","following_url":"https://api.github.com/users/andy-slac/following{/other_user}","gists_url":"https://api.github.com/users/andy-slac/gists{/gist_id}","starred_url":"https://api.github.com/users/andy-slac/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/andy-slac/subscriptions","organizations_url":"https://api.github.com/users/andy-slac/orgs","repos_url":"https://api.github.com/users/andy-slac/repos","events_url":"https://api.github.com/users/andy-slac/events{/privacy}","received_events_url":"https://api.github.com/users/andy-slac/received_events","type":"User","site_admin":false},"body":"Should probably raise an exception if query is not found.","created_at":"2015-11-18T19:31:40Z","updated_at":"2015-11-18T19:31:40Z","html_url":"https://github.com/lsst/qserv/pull/156#discussion_r45247711","pull_request_url":"https://api.github.com/repos/lsst/qserv/pulls/156","_links":{"self":{"href":"https://api.github.com/repos/lsst/qserv/pulls/comments/45247711"},"html":{"href":"https://github.com/lsst/qserv/pull/156#discussion_r45247711"},"pull_request":{"href":"https://api.github.com/repos/lsst/qserv/pulls/156"}}},"pull_request":{"url":"https://api.github.com/repos/lsst/qserv/pulls/156","id":51008303,"html_url":"https://github.com/lsst/qserv/pull/156","diff_url":"https://github.com/lsst/qserv/pull/156.diff","patch_url":"https://github.com/lsst/qserv/pull/156.patch","issue_url":"https://api.github.com/repos/lsst/qserv/issues/156","number":156,"state":"open","locked":false,"title":"Add header file that describes the shared scan interface.","user":{"login":"abh3","id":2657143,"avatar_url":"https://avatars.githubusercontent.com/u/2657143?v=3","gravatar_id":"","url":"https://api.github.com/users/abh3","html_url":"https://github.com/abh3","followers_url":"https://api.github.com/users/abh3/followers","following_url":"https://api.github.com/users/abh3/following{/other_user}","gists_url":"https://api.github.com/users/abh3/gists{/gist_id}","starred_url":"https://api.github.com/users/abh3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/abh3/subscriptions","organizations_url":"https://api.github.com/users/abh3/orgs","repos_url":"https://api.github.com/users/abh3/repos","events_url":"https://api.github.com/users/abh3/events{/privacy}","received_events_url":"https://api.github.com/users/abh3/received_events","type":"User","site_admin":false},"body":"The subject line says it all.","created_at":"2015-11-17T21:37:32Z","updated_at":"2015-11-18T19:31:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"87847b2619c95bda98a1db4045d3bfd2f1d04b20","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/lsst/qserv/pulls/156/commits","review_comments_url":"https://api.github.com/repos/lsst/qserv/pulls/156/comments","review_comment_url":"https://api.github.com/repos/lsst/qserv/pulls/comments{/number}","comments_url":"https://api.github.com/repos/lsst/qserv/issues/156/comments","statuses_url":"https://api.github.com/repos/lsst/qserv/statuses/0a78e1cb63a73a911413067652a177fe0f4268eb","head":{"label":"lsst:ticket/DM-3755","ref":"ticket/DM-3755","sha":"0a78e1cb63a73a911413067652a177fe0f4268eb","user":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"repo":{"id":23013460,"name":"qserv","full_name":"lsst/qserv","owner":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/lsst/qserv","description":"LSST Query Services","fork":false,"url":"https://api.github.com/repos/lsst/qserv","forks_url":"https://api.github.com/repos/lsst/qserv/forks","keys_url":"https://api.github.com/repos/lsst/qserv/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lsst/qserv/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lsst/qserv/teams","hooks_url":"https://api.github.com/repos/lsst/qserv/hooks","issue_events_url":"https://api.github.com/repos/lsst/qserv/issues/events{/number}","events_url":"https://api.github.com/repos/lsst/qserv/events","assignees_url":"https://api.github.com/repos/lsst/qserv/assignees{/user}","branches_url":"https://api.github.com/repos/lsst/qserv/branches{/branch}","tags_url":"https://api.github.com/repos/lsst/qserv/tags","blobs_url":"https://api.github.com/repos/lsst/qserv/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lsst/qserv/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lsst/qserv/git/refs{/sha}","trees_url":"https://api.github.com/repos/lsst/qserv/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lsst/qserv/statuses/{sha}","languages_url":"https://api.github.com/repos/lsst/qserv/languages","stargazers_url":"https://api.github.com/repos/lsst/qserv/stargazers","contributors_url":"https://api.github.com/repos/lsst/qserv/contributors","subscribers_url":"https://api.github.com/repos/lsst/qserv/subscribers","subscription_url":"https://api.github.com/repos/lsst/qserv/subscription","commits_url":"https://api.github.com/repos/lsst/qserv/commits{/sha}","git_commits_url":"https://api.github.com/repos/lsst/qserv/git/commits{/sha}","comments_url":"https://api.github.com/repos/lsst/qserv/comments{/number}","issue_comment_url":"https://api.github.com/repos/lsst/qserv/issues/comments{/number}","contents_url":"https://api.github.com/repos/lsst/qserv/contents/{+path}","compare_url":"https://api.github.com/repos/lsst/qserv/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lsst/qserv/merges","archive_url":"https://api.github.com/repos/lsst/qserv/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lsst/qserv/downloads","issues_url":"https://api.github.com/repos/lsst/qserv/issues{/number}","pulls_url":"https://api.github.com/repos/lsst/qserv/pulls{/number}","milestones_url":"https://api.github.com/repos/lsst/qserv/milestones{/number}","notifications_url":"https://api.github.com/repos/lsst/qserv/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lsst/qserv/labels{/name}","releases_url":"https://api.github.com/repos/lsst/qserv/releases{/id}","created_at":"2014-08-16T07:50:36Z","updated_at":"2015-05-08T02:01:15Z","pushed_at":"2015-11-18T17:34:01Z","git_url":"git://github.com/lsst/qserv.git","ssh_url":"git@github.com:lsst/qserv.git","clone_url":"https://github.com/lsst/qserv.git","svn_url":"https://github.com/lsst/qserv","homepage":"http://dm.lsst.org/","size":14339,"stargazers_count":4,"watchers_count":4,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":6,"forks":5,"open_issues":6,"watchers":4,"default_branch":"master"}},"base":{"label":"lsst:master","ref":"master","sha":"25295192bddaec16ed080a531b9fbe45bf62e377","user":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"repo":{"id":23013460,"name":"qserv","full_name":"lsst/qserv","owner":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/lsst/qserv","description":"LSST Query Services","fork":false,"url":"https://api.github.com/repos/lsst/qserv","forks_url":"https://api.github.com/repos/lsst/qserv/forks","keys_url":"https://api.github.com/repos/lsst/qserv/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lsst/qserv/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lsst/qserv/teams","hooks_url":"https://api.github.com/repos/lsst/qserv/hooks","issue_events_url":"https://api.github.com/repos/lsst/qserv/issues/events{/number}","events_url":"https://api.github.com/repos/lsst/qserv/events","assignees_url":"https://api.github.com/repos/lsst/qserv/assignees{/user}","branches_url":"https://api.github.com/repos/lsst/qserv/branches{/branch}","tags_url":"https://api.github.com/repos/lsst/qserv/tags","blobs_url":"https://api.github.com/repos/lsst/qserv/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lsst/qserv/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lsst/qserv/git/refs{/sha}","trees_url":"https://api.github.com/repos/lsst/qserv/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lsst/qserv/statuses/{sha}","languages_url":"https://api.github.com/repos/lsst/qserv/languages","stargazers_url":"https://api.github.com/repos/lsst/qserv/stargazers","contributors_url":"https://api.github.com/repos/lsst/qserv/contributors","subscribers_url":"https://api.github.com/repos/lsst/qserv/subscribers","subscription_url":"https://api.github.com/repos/lsst/qserv/subscription","commits_url":"https://api.github.com/repos/lsst/qserv/commits{/sha}","git_commits_url":"https://api.github.com/repos/lsst/qserv/git/commits{/sha}","comments_url":"https://api.github.com/repos/lsst/qserv/comments{/number}","issue_comment_url":"https://api.github.com/repos/lsst/qserv/issues/comments{/number}","contents_url":"https://api.github.com/repos/lsst/qserv/contents/{+path}","compare_url":"https://api.github.com/repos/lsst/qserv/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lsst/qserv/merges","archive_url":"https://api.github.com/repos/lsst/qserv/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lsst/qserv/downloads","issues_url":"https://api.github.com/repos/lsst/qserv/issues{/number}","pulls_url":"https://api.github.com/repos/lsst/qserv/pulls{/number}","milestones_url":"https://api.github.com/repos/lsst/qserv/milestones{/number}","notifications_url":"https://api.github.com/repos/lsst/qserv/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lsst/qserv/labels{/name}","releases_url":"https://api.github.com/repos/lsst/qserv/releases{/id}","created_at":"2014-08-16T07:50:36Z","updated_at":"2015-05-08T02:01:15Z","pushed_at":"2015-11-18T17:34:01Z","git_url":"git://github.com/lsst/qserv.git","ssh_url":"git@github.com:lsst/qserv.git","clone_url":"https://github.com/lsst/qserv.git","svn_url":"https://github.com/lsst/qserv","homepage":"http://dm.lsst.org/","size":14339,"stargazers_count":4,"watchers_count":4,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":6,"forks":5,"open_issues":6,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/lsst/qserv/pulls/156"},"html":{"href":"https://github.com/lsst/qserv/pull/156"},"issue":{"href":"https://api.github.com/repos/lsst/qserv/issues/156"},"comments":{"href":"https://api.github.com/repos/lsst/qserv/issues/156/comments"},"review_comments":{"href":"https://api.github.com/repos/lsst/qserv/pulls/156/comments"},"review_comment":{"href":"https://api.github.com/repos/lsst/qserv/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/lsst/qserv/pulls/156/commits"},"statuses":{"href":"https://api.github.com/repos/lsst/qserv/statuses/0a78e1cb63a73a911413067652a177fe0f4268eb"}}}}