{"action":"created","comment":{"url":"https://api.github.com/repos/motech/modules/pulls/comments/40096415","id":40096415,"diff_hunk":"@@ -4,6 +4,227 @@\n Hub Module\n ==========\n \n-To be written.\n+.. contents::\n+    :depth: 3\n \n-If you'd like to author this topic, please assign yourself `MOTECH-964 <https://applab.atlassian.net/browse/MOTECH-964>`_.\n+############\n+Introduction\n+############\n+\n+The Hub module is an implementation of PubSubHubbub Hub specification (PubSubHubbub is a simple publication - subscription\n+protocol). MOTECH Hub implementation exposes API for publishers and subscribers, allowing publishing and distributing\n+content to all interested subscribers when subscribed resources are updated. With help of MOTECH Hub any external module\n+can subscribe to a specific resource and be notified when it change as well as can act as publisher to make content\n+available for other modules.\n+\n+#####\n+Setup\n+#####\n+\n+Setup fields\n+------------\n+\n+In order to use MOTECH Hub module hub base url have to be set before performing any subscribe/unsubscribe/publish requests.\n+It can be done by REST call or by Hub module UI configuration panel. UI configuration panel also offers possibility to\n+set retry count and retry interval parameters. For explanation of these parameters please look at table below.\n+\n++---------------+-----------------------------------------------------------------------------------------------------+\n+|Parameter      |Description                                                                                          |\n++===============+=====================================================================================================+\n+|hubBaseUrl     |The base URL of the hub server. Will be used while distributing the updated content of the topic to  |\n+|               |the subscribers, as part of the Link Header.                                                         |\n++---------------+-----------------------------------------------------------------------------------------------------+\n+|retry.count    |The number of request send retries that Hub module will take in case of failed hub request.          |\n++---------------+-----------------------------------------------------------------------------------------------------+\n+|retry.interval |The time between request retries in case of failed hub request.                                      |\n++---------------+-----------------------------------------------------------------------------------------------------+\n+\n+Configure by UI\n+---------------\n+\n+To configure Hub module by UI run MOTECH with Hub module installed and in Admin panel go to Manage Modules. Click\n+Settings in Action column for Hub module. Now you can set values for fields described above. After configuration is done\n+choose \"Submit\" or \"Submit and restart\".\n+\n+Configure by REST CALL\n+----------------------\n+\n+To configure hub base url by REST send HTTP ``POST`` call to:\n+\n+ ::\n+\n+    http://{motech-server}/{motech-war-file}/module/hub/settings\n+\n+with content type set to ``application/json`` and request body JSON structured as shown below:\n+\n+.. code-block:: json\n+\n+    {\n+        settings: {\n+            hubBaseUrl: \"your_url\"\n+        }\n+    }\n+\n+.. note::\n+\n+    Using REST you can set only ``hubBaseUrl`` parameter. If you need to change ``retry.count`` or ``retry.interval``\n+    you have to use the UI.\n+\n+#########################\n+Subscribing/Unsubscribing\n+#########################\n+\n+Subscribing/Unsubscribing process\n+---------------------------------\n+\n+To make a subscription the subscriber first have to send subscription request to the hub. Input parameters are validated\n+by ``HubValidator`` and if validation passes without error then the Hub responds to the subscriber with an HTTP status\n+``202 Accepted``. This is only for acknowledge subscriber that his subscription request reached the Hub. After that the\n+Hub starts intent verification in order to prevent an attacker from creating unwanted subscriptions or unsubscribing from\n+desired ones.\n+\n+The subscriber must confirm that he want to make pending subscription. The hub sends to the subscriber HTTP ``GET``\n+request with ``hub.challenge`` parameter in it. The subscriber must respond with an HTTP success (2xx) code with a response\n+body equal to the ``hub.challenge`` parameter. The subscriptions is made if described process will pass without any failures.\n+\n+Validation and intent verification also apply for unsubscribing.\n+\n+From moment at which the subscription is made the subscriber will be notified about changes in subscribed resource on\n+his ``hub.callback`` URL, defined when subscription request was send. Notifications will be turned off after successful\n+unsubscribe request or when hub.lease_seconds pass.\n+\n+Please look at the end of this section to find description of all fields used in subscribing/unsubscribing requests.\n+\n+REST CALLs\n+----------\n+\n+One of two methods to make (un)subscription is HTTP REST call. To make (un)subscription send HTTP ``POST`` request to:\n+\n+    ::\n+\n+        http://{motech-server}/{motech-war-file}/module/hub/?hub.callback={callbackUrl}&hub.mode={hubMode}&hub.topic={topic}&hub.lease_seconds={lease_seconds}&hub.secret={secret}\n+\n+with content type set to ``application/x-www-form-urlencoded`` and ``{hubMode}`` to one of two literal strings \"subscribe\"\n+or \"unsubscribe\" depending on the goal of the request. For detailed description of parameters refer to the table at\n+the end of this section.\n+\n+The Hub will respond to URL passed as a callback parameter with HTTP ``GET`` request with the following query string\n+arguments appended:\n+\n+    - :code:`hub.mode`: The literal string \"subscribe\" or \"unsubscribe\", which matches the value from original request.\n+    - :code:`hub.topic`: The topic URL given in the corresponding subscription request.\n+    - :code:`hub.challenge`: A hub-generated random string used for intent verification.\n+\n+To confirm (un)subscription the subscriber must respond with an HTTP success code (2xx) with a response body equal to the\n+``hub.challenge`` parameter.\n+\n+OSGi Services\n+-------------\n+\n+The Hub module expose OSGi ``SubscriptionService`` interface for subscribing:\n+\n+.. code-block:: java\n+\n+    public interface SubscriptionService {\n+\n+        void subscribe(String callbackUrl, Modes hubMode, String topic,\n+                String leaseSeconds, String secret) throws HubException;\n+\n+    }\n+\n+To subscribe with this service just call subscribe method passing all the parameters. Detailed description of the parameters\n+is shown in table below.\n+\n+Parameters description\n+----------------------\n+\n+Find description of the parameters used in (ub)subscribing in the table below:\n+\n++---------------+----------------+------------------------------------------------------------------------------------+\n+|Parameter      |OSGi Service    |Description                                                                         |\n+|               |parameter type  |                                                                                    |\n++===============+================+====================================================================================+\n+|callbackUrl    |String          |The subscriber's callback URL. Notifications about updates in subscribed topic will |\n+|               |                |be delivered to this URL.                                                           |\n++---------------+----------------+------------------------------------------------------------------------------------+\n+|hubMode        |Modes           |In REST call this parameter have to be either literal \"subscribe\" or \"unsubscribe\"  |\n+|               |                |string. In OSGi service enum ``Modes`` class is used, so it can take value either   |\n+|               |                |``Modes.SUBSCRIBE`` or ``Modes.UNSUBSCRIBE``. The mode represents the goal of the   |\n+|               |                |request.                                                                            |\n++---------------+----------------+------------------------------------------------------------------------------------+\n+|topic          |String          |The topic URL that the subscriber wishes to subscribe to or unsubscribe from. Topic |\n+|               |                |is an URL to any resource that notifies the Hub about updates.                      |\n++---------------+----------------+------------------------------------------------------------------------------------+\n+|leaseSeconds   |String          |Number of seconds for which the subscriber would like to have the subscription      |\n+|               |                |active. After this time pass subscription need to be renewed.                       |\n++---------------+----------------+------------------------------------------------------------------------------------+\n+|secret         |String          |A subscriber-provided secret string that will be used to compute an HMAC digest for |\n+|               |                |authorized content distribution.                                                    |\n++---------------+----------------+------------------------------------------------------------------------------------+\n+|hub.challenge  |                |The parameter sent by the Hub in GET request in process of intent verification.     |\n+|               |                |The subscriber must respond with HTTP success (2xx) status with challenge parameter |\n+|               |                |in response body to confirm (un)subscription.                                       |\n++---------------+----------------+------------------------------------------------------------------------------------+\n+\n+##########\n+Publishing\n+##########\n+\n+Whenever there is an update in topic, the publisher notifies the hub providing the resource URL (topic) which\n+is updated. Then hub fetches the updated content and distributes it to all the active subscribers of that topic.\n+\n+REST CALL\n+---------\n+\n+To notify about update by REST call send HTTP ``POST`` request to\n+\n+    ::\n+\n+        http://{motech-server}/{motech-war-file}/module/hub/?&hub.mode={hubMode}&hub.url={url}\n+\n+with content type set to ``application/x-www-form-urlencoded``, ``{hubMode}`` to literal string \"publish\" and\n+``{url}`` to updated topic URL.\n+\n+OSGI Service\n+------------\n+\n+The Hub module expose OSGi ``ContentDistributionService`` interface for publishing:\n+\n+.. code-block:: java\n+\n+    public interface ContentDistributionService {\n+\n+        void distribute(String url);\n+\n+    }\n+\n+To publish with this service update your topic, then just call distribute method providing updated topic URL.\n+\n+##############\n+Error handling\n+##############\n+\n+Errors that occurs when using Hub module are wrapped in a custom ``HubException`` exception class. This class contains\n+``reason`` field that contain description of what caused failure and ``HubErrors`` object which contains more detailed\n+information about error, which at least are ``message``, ``code`` and ``httpStatus``. Please refer to table shown below","path":"docs/source/hub.rst","position":208,"original_position":208,"commit_id":"e3e3e42934e62ba74bf12bec80510589d46861af","original_commit_id":"e3e3e42934e62ba74bf12bec80510589d46861af","user":{"login":"sebbrudzinski","id":8852946,"avatar_url":"https://avatars.githubusercontent.com/u/8852946?v=3","gravatar_id":"","url":"https://api.github.com/users/sebbrudzinski","html_url":"https://github.com/sebbrudzinski","followers_url":"https://api.github.com/users/sebbrudzinski/followers","following_url":"https://api.github.com/users/sebbrudzinski/following{/other_user}","gists_url":"https://api.github.com/users/sebbrudzinski/gists{/gist_id}","starred_url":"https://api.github.com/users/sebbrudzinski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sebbrudzinski/subscriptions","organizations_url":"https://api.github.com/users/sebbrudzinski/orgs","repos_url":"https://api.github.com/users/sebbrudzinski/repos","events_url":"https://api.github.com/users/sebbrudzinski/events{/privacy}","received_events_url":"https://api.github.com/users/sebbrudzinski/received_events","type":"User","site_admin":false},"body":"I don't get this part.. Do you mean that the field contains information about the message, code and http status for which the error occured?","created_at":"2015-09-22T14:57:26Z","updated_at":"2015-09-22T14:57:26Z","html_url":"https://github.com/motech/modules/pull/28#discussion_r40096415","pull_request_url":"https://api.github.com/repos/motech/modules/pulls/28","_links":{"self":{"href":"https://api.github.com/repos/motech/modules/pulls/comments/40096415"},"html":{"href":"https://github.com/motech/modules/pull/28#discussion_r40096415"},"pull_request":{"href":"https://api.github.com/repos/motech/modules/pulls/28"}}},"pull_request":{"url":"https://api.github.com/repos/motech/modules/pulls/28","id":45645364,"html_url":"https://github.com/motech/modules/pull/28","diff_url":"https://github.com/motech/modules/pull/28.diff","patch_url":"https://github.com/motech/modules/pull/28.patch","issue_url":"https://api.github.com/repos/motech/modules/issues/28","number":28,"state":"open","locked":false,"title":"MOTECH-964: Created topic for Hub Module","user":{"login":"LukSkarDev","id":3722203,"avatar_url":"https://avatars.githubusercontent.com/u/3722203?v=3","gravatar_id":"","url":"https://api.github.com/users/LukSkarDev","html_url":"https://github.com/LukSkarDev","followers_url":"https://api.github.com/users/LukSkarDev/followers","following_url":"https://api.github.com/users/LukSkarDev/following{/other_user}","gists_url":"https://api.github.com/users/LukSkarDev/gists{/gist_id}","starred_url":"https://api.github.com/users/LukSkarDev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LukSkarDev/subscriptions","organizations_url":"https://api.github.com/users/LukSkarDev/orgs","repos_url":"https://api.github.com/users/LukSkarDev/repos","events_url":"https://api.github.com/users/LukSkarDev/events{/privacy}","received_events_url":"https://api.github.com/users/LukSkarDev/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-09-22T10:03:19Z","updated_at":"2015-09-22T14:57:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7080e8a73c7088464f73acc566da0c145e0c61e8","assignee":{"login":"sebbrudzinski","id":8852946,"avatar_url":"https://avatars.githubusercontent.com/u/8852946?v=3","gravatar_id":"","url":"https://api.github.com/users/sebbrudzinski","html_url":"https://github.com/sebbrudzinski","followers_url":"https://api.github.com/users/sebbrudzinski/followers","following_url":"https://api.github.com/users/sebbrudzinski/following{/other_user}","gists_url":"https://api.github.com/users/sebbrudzinski/gists{/gist_id}","starred_url":"https://api.github.com/users/sebbrudzinski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sebbrudzinski/subscriptions","organizations_url":"https://api.github.com/users/sebbrudzinski/orgs","repos_url":"https://api.github.com/users/sebbrudzinski/repos","events_url":"https://api.github.com/users/sebbrudzinski/events{/privacy}","received_events_url":"https://api.github.com/users/sebbrudzinski/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/motech/modules/pulls/28/commits","review_comments_url":"https://api.github.com/repos/motech/modules/pulls/28/comments","review_comment_url":"https://api.github.com/repos/motech/modules/pulls/comments{/number}","comments_url":"https://api.github.com/repos/motech/modules/issues/28/comments","statuses_url":"https://api.github.com/repos/motech/modules/statuses/e3e3e42934e62ba74bf12bec80510589d46861af","head":{"label":"LukSkarDev:MOTECH-964","ref":"MOTECH-964","sha":"e3e3e42934e62ba74bf12bec80510589d46861af","user":{"login":"LukSkarDev","id":3722203,"avatar_url":"https://avatars.githubusercontent.com/u/3722203?v=3","gravatar_id":"","url":"https://api.github.com/users/LukSkarDev","html_url":"https://github.com/LukSkarDev","followers_url":"https://api.github.com/users/LukSkarDev/followers","following_url":"https://api.github.com/users/LukSkarDev/following{/other_user}","gists_url":"https://api.github.com/users/LukSkarDev/gists{/gist_id}","starred_url":"https://api.github.com/users/LukSkarDev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LukSkarDev/subscriptions","organizations_url":"https://api.github.com/users/LukSkarDev/orgs","repos_url":"https://api.github.com/users/LukSkarDev/repos","events_url":"https://api.github.com/users/LukSkarDev/events{/privacy}","received_events_url":"https://api.github.com/users/LukSkarDev/received_events","type":"User","site_admin":false},"repo":{"id":42447903,"name":"modules","full_name":"LukSkarDev/modules","owner":{"login":"LukSkarDev","id":3722203,"avatar_url":"https://avatars.githubusercontent.com/u/3722203?v=3","gravatar_id":"","url":"https://api.github.com/users/LukSkarDev","html_url":"https://github.com/LukSkarDev","followers_url":"https://api.github.com/users/LukSkarDev/followers","following_url":"https://api.github.com/users/LukSkarDev/following{/other_user}","gists_url":"https://api.github.com/users/LukSkarDev/gists{/gist_id}","starred_url":"https://api.github.com/users/LukSkarDev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LukSkarDev/subscriptions","organizations_url":"https://api.github.com/users/LukSkarDev/orgs","repos_url":"https://api.github.com/users/LukSkarDev/repos","events_url":"https://api.github.com/users/LukSkarDev/events{/privacy}","received_events_url":"https://api.github.com/users/LukSkarDev/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/LukSkarDev/modules","description":"","fork":true,"url":"https://api.github.com/repos/LukSkarDev/modules","forks_url":"https://api.github.com/repos/LukSkarDev/modules/forks","keys_url":"https://api.github.com/repos/LukSkarDev/modules/keys{/key_id}","collaborators_url":"https://api.github.com/repos/LukSkarDev/modules/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/LukSkarDev/modules/teams","hooks_url":"https://api.github.com/repos/LukSkarDev/modules/hooks","issue_events_url":"https://api.github.com/repos/LukSkarDev/modules/issues/events{/number}","events_url":"https://api.github.com/repos/LukSkarDev/modules/events","assignees_url":"https://api.github.com/repos/LukSkarDev/modules/assignees{/user}","branches_url":"https://api.github.com/repos/LukSkarDev/modules/branches{/branch}","tags_url":"https://api.github.com/repos/LukSkarDev/modules/tags","blobs_url":"https://api.github.com/repos/LukSkarDev/modules/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/LukSkarDev/modules/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/LukSkarDev/modules/git/refs{/sha}","trees_url":"https://api.github.com/repos/LukSkarDev/modules/git/trees{/sha}","statuses_url":"https://api.github.com/repos/LukSkarDev/modules/statuses/{sha}","languages_url":"https://api.github.com/repos/LukSkarDev/modules/languages","stargazers_url":"https://api.github.com/repos/LukSkarDev/modules/stargazers","contributors_url":"https://api.github.com/repos/LukSkarDev/modules/contributors","subscribers_url":"https://api.github.com/repos/LukSkarDev/modules/subscribers","subscription_url":"https://api.github.com/repos/LukSkarDev/modules/subscription","commits_url":"https://api.github.com/repos/LukSkarDev/modules/commits{/sha}","git_commits_url":"https://api.github.com/repos/LukSkarDev/modules/git/commits{/sha}","comments_url":"https://api.github.com/repos/LukSkarDev/modules/comments{/number}","issue_comment_url":"https://api.github.com/repos/LukSkarDev/modules/issues/comments{/number}","contents_url":"https://api.github.com/repos/LukSkarDev/modules/contents/{+path}","compare_url":"https://api.github.com/repos/LukSkarDev/modules/compare/{base}...{head}","merges_url":"https://api.github.com/repos/LukSkarDev/modules/merges","archive_url":"https://api.github.com/repos/LukSkarDev/modules/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/LukSkarDev/modules/downloads","issues_url":"https://api.github.com/repos/LukSkarDev/modules/issues{/number}","pulls_url":"https://api.github.com/repos/LukSkarDev/modules/pulls{/number}","milestones_url":"https://api.github.com/repos/LukSkarDev/modules/milestones{/number}","notifications_url":"https://api.github.com/repos/LukSkarDev/modules/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/LukSkarDev/modules/labels{/name}","releases_url":"https://api.github.com/repos/LukSkarDev/modules/releases{/id}","created_at":"2015-09-14T12:42:34Z","updated_at":"2015-09-14T12:42:38Z","pushed_at":"2015-09-22T12:37:52Z","git_url":"git://github.com/LukSkarDev/modules.git","ssh_url":"git@github.com:LukSkarDev/modules.git","clone_url":"https://github.com/LukSkarDev/modules.git","svn_url":"https://github.com/LukSkarDev/modules","homepage":null,"size":30645,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"motech:master","ref":"master","sha":"b031a539b5647316430ba24591dca6d4ecd565f3","user":{"login":"motech","id":477919,"avatar_url":"https://avatars.githubusercontent.com/u/477919?v=3","gravatar_id":"","url":"https://api.github.com/users/motech","html_url":"https://github.com/motech","followers_url":"https://api.github.com/users/motech/followers","following_url":"https://api.github.com/users/motech/following{/other_user}","gists_url":"https://api.github.com/users/motech/gists{/gist_id}","starred_url":"https://api.github.com/users/motech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/motech/subscriptions","organizations_url":"https://api.github.com/users/motech/orgs","repos_url":"https://api.github.com/users/motech/repos","events_url":"https://api.github.com/users/motech/events{/privacy}","received_events_url":"https://api.github.com/users/motech/received_events","type":"Organization","site_admin":false},"repo":{"id":19785525,"name":"modules","full_name":"motech/modules","owner":{"login":"motech","id":477919,"avatar_url":"https://avatars.githubusercontent.com/u/477919?v=3","gravatar_id":"","url":"https://api.github.com/users/motech","html_url":"https://github.com/motech","followers_url":"https://api.github.com/users/motech/followers","following_url":"https://api.github.com/users/motech/following{/other_user}","gists_url":"https://api.github.com/users/motech/gists{/gist_id}","starred_url":"https://api.github.com/users/motech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/motech/subscriptions","organizations_url":"https://api.github.com/users/motech/orgs","repos_url":"https://api.github.com/users/motech/repos","events_url":"https://api.github.com/users/motech/events{/privacy}","received_events_url":"https://api.github.com/users/motech/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/motech/modules","description":" Mobile Technology for Community Health - Modules","fork":false,"url":"https://api.github.com/repos/motech/modules","forks_url":"https://api.github.com/repos/motech/modules/forks","keys_url":"https://api.github.com/repos/motech/modules/keys{/key_id}","collaborators_url":"https://api.github.com/repos/motech/modules/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/motech/modules/teams","hooks_url":"https://api.github.com/repos/motech/modules/hooks","issue_events_url":"https://api.github.com/repos/motech/modules/issues/events{/number}","events_url":"https://api.github.com/repos/motech/modules/events","assignees_url":"https://api.github.com/repos/motech/modules/assignees{/user}","branches_url":"https://api.github.com/repos/motech/modules/branches{/branch}","tags_url":"https://api.github.com/repos/motech/modules/tags","blobs_url":"https://api.github.com/repos/motech/modules/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/motech/modules/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/motech/modules/git/refs{/sha}","trees_url":"https://api.github.com/repos/motech/modules/git/trees{/sha}","statuses_url":"https://api.github.com/repos/motech/modules/statuses/{sha}","languages_url":"https://api.github.com/repos/motech/modules/languages","stargazers_url":"https://api.github.com/repos/motech/modules/stargazers","contributors_url":"https://api.github.com/repos/motech/modules/contributors","subscribers_url":"https://api.github.com/repos/motech/modules/subscribers","subscription_url":"https://api.github.com/repos/motech/modules/subscription","commits_url":"https://api.github.com/repos/motech/modules/commits{/sha}","git_commits_url":"https://api.github.com/repos/motech/modules/git/commits{/sha}","comments_url":"https://api.github.com/repos/motech/modules/comments{/number}","issue_comment_url":"https://api.github.com/repos/motech/modules/issues/comments{/number}","contents_url":"https://api.github.com/repos/motech/modules/contents/{+path}","compare_url":"https://api.github.com/repos/motech/modules/compare/{base}...{head}","merges_url":"https://api.github.com/repos/motech/modules/merges","archive_url":"https://api.github.com/repos/motech/modules/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/motech/modules/downloads","issues_url":"https://api.github.com/repos/motech/modules/issues{/number}","pulls_url":"https://api.github.com/repos/motech/modules/pulls{/number}","milestones_url":"https://api.github.com/repos/motech/modules/milestones{/number}","notifications_url":"https://api.github.com/repos/motech/modules/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/motech/modules/labels{/name}","releases_url":"https://api.github.com/repos/motech/modules/releases{/id}","created_at":"2014-05-14T15:41:17Z","updated_at":"2015-09-14T18:16:42Z","pushed_at":"2015-09-22T12:37:53Z","git_url":"git://github.com/motech/modules.git","ssh_url":"git@github.com:motech/modules.git","clone_url":"https://github.com/motech/modules.git","svn_url":"https://github.com/motech/modules","homepage":"http://modules.motechproject.org","size":32556,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":17,"mirror_url":null,"open_issues_count":8,"forks":17,"open_issues":8,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/motech/modules/pulls/28"},"html":{"href":"https://github.com/motech/modules/pull/28"},"issue":{"href":"https://api.github.com/repos/motech/modules/issues/28"},"comments":{"href":"https://api.github.com/repos/motech/modules/issues/28/comments"},"review_comments":{"href":"https://api.github.com/repos/motech/modules/pulls/28/comments"},"review_comment":{"href":"https://api.github.com/repos/motech/modules/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/motech/modules/pulls/28/commits"},"statuses":{"href":"https://api.github.com/repos/motech/modules/statuses/e3e3e42934e62ba74bf12bec80510589d46861af"}}}}