{"action":"created","comment":{"url":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/comments/181787982","pull_request_review_id":112473238,"id":181787982,"diff_hunk":"@@ -0,0 +1,166 @@\n+\"\"\"\n+STDIO handling threads for netcat and airgap modes\n+\n+stdInput thread: receives hex-encoded bitmessage objects on STDIN\n+Supported input formats, format is auto-detected:\n+  - each line a hex-encoded object\n+  - each line formatted: hex_timestamp - tab - hex-encoded_object\n+    (the output format of netcat mode)\n+\n+objectStdOut thread: replaces the objectProcessor thread in netcat mode,\n+  outputs to STDOUT in format: hex_timestamp - tab - hex-encoded_object\n+\"\"\"\n+\n+import threading\n+import time\n+from struct import unpack\n+from binascii import hexlify, unhexlify\n+from addresses import decodeVarint, calculateInventoryHash\n+from debug import logger\n+\n+import protocol\n+import queues\n+import state\n+import shutdown\n+import shared # statusIconColor\n+from inventory import Inventory\n+from helper_sql import sqlQuery, sqlExecute, SqlBulkExecute\n+\n+stdInputMode = 'netcat'  # process STDIN in netcat mode by default\n+netcatExitOnEOF = True   # exit program if EOF on STDIN\n+\n+class stdInput(threading.Thread):\n+    \"\"\"\n+    Standard Input thread reads objects from STDIN, posts them to Inventory\n+    \"\"\"\n+\n+    def __init__(self, inputSrc):\n+        threading.Thread.__init__(self, name=\"stdInput\")\n+        self.inputSrc = inputSrc\n+        logger.info('stdInput thread started.')\n+\n+    def run(self):\n+        while True:\n+            # read a line in hex encoding\n+            line = self.inputSrc.readline()\n+            if len(line) == 0:\n+                logger.info(\"STDIN: End of input\")\n+                if netcatExitOnEOF:\n+                    shutdown.doCleanShutdown()\n+                break\n+\n+            hexObject = line.rstrip()\n+            hexTStamp = ''\n+\n+            # detect timestamp-tab-object format (as output by netcat mode)\n+            if \"\\t\" in hexObject:\n+                hexTStamp = hexObject.split(\"\\t\")[0]\n+                hexObject = hexObject.split(\"\\t\")[-1]\n+\n+            # unhex the input with error rejection\n+            try:\n+                binObject = unhexlify(hexObject)\n+            except Exception:\n+                logger.info(\"STDIN: Invalid input format\")\n+                continue\n+\n+            # sanity check on object size\n+            if len(binObject) < 22:\n+                logger.info(\"STDIN: Invalid object size\")\n+                continue\n+\n+            if not state.enableNetwork and state.enableGUI:\n+                # in airgap mode, trick the status icon that we are in fact\n+                #   NOT waiting for a connection\n+                # (may be removed after impact analysis)\n+                shared.statusIconColor = 'yellow'\n+\n+            if stdInputMode == 'airgap':\n+                # airgap mode uses the timestamp\n+                # unhex the timestamp with error rejection\n+                if len(hexTStamp) == 16:\n+                    try:\n+                        # stdioStamp, = unpack('>Q', unhexlify(hexTStamp))\n+                        _, = unpack('>Q', unhexlify(hexTStamp))\n+                    except Exception:\n+                        logger.info(\"STDIN: Invalid timestamp format: \" + hexTStamp)\n+                        continue\n+\n+            # check that proof of work is sufficient.\n+            if not protocol.isProofOfWorkSufficient(binObject):\n+                logger.info('STDIN: Insufficient Proof of Work')\n+                continue\n+\n+            # extract expiry time, object type\n+            eTime, = unpack('>Q', binObject[8:16])\n+            objectType, = unpack('>I', binObject[16:20])\n+\n+            # extract version number and stream number\n+            readPosition = 20  # bypass the nonce, time, and object type\n+            # versionNumber, versionLength\n+            _, versionLength = decodeVarint(binObject[readPosition:readPosition + 10])\n+            readPosition += versionLength\n+            streamNumber, streamNumberLength = decodeVarint(binObject[readPosition:readPosition + 10])\n+            readPosition += streamNumberLength\n+\n+            # calculate inventory hash\n+            inventoryHash = calculateInventoryHash(binObject)\n+\n+            # duplicate check on inventory hash (both netcat and airgap)\n+            if inventoryHash in Inventory():\n+                logger.info(\"STDIN: Already got object \" + hexlify(inventoryHash))\n+                continue\n+\n+            # in netcat mode, push object to inventory and id to output queue\n+            if stdInputMode == 'netcat':\n+                Inventory()[inventoryHash] = (objectType, streamNumber, binObject, eTime, '')\n+                logger.info(\"STDIN: Accepted object (type=%u) \" % objectType + hexlify(inventoryHash))\n+                queues.invQueue.put((streamNumber, inventoryHash))\n+\n+            # honour global shutdown flag\n+            if state.shutdown != 0:\n+                logger.info('stdInput thread shutdown.')\n+                break\n+\n+class objectStdOut(threading.Thread):\n+    \"\"\"\n+    The objectStdOut thread receives network objects from the receiveDataThreads.\n+    \"\"\"\n+    def __init__(self):\n+        threading.Thread.__init__(self, name=\"objectStdOut\")\n+\n+        # REFACTOR THIS with objectProcessor into objectProcessorQueue\n+        queryreturn = sqlQuery(\n+            '''SELECT objecttype, data FROM objectprocessorqueue''')\n+        for row in queryreturn:\n+            objectType, data = row\n+            queues.objectProcessorQueue.put((objectType, data))\n+        sqlExecute('''DELETE FROM objectprocessorqueue''')\n+        logger.debug('Loaded %s objects from disk into the objectProcessorQueue.' % str(len(queryreturn)))","path":"src/std_io.py","position":141,"original_position":139,"commit_id":"63893b53f8db0e0b107e4fd34b6684bba8d67139","original_commit_id":"e9425c8bfb9c6f25c60848a0ea3af0f378e7bd3b","user":{"login":"f97ada87","id":32196103,"avatar_url":"https://avatars3.githubusercontent.com/u/32196103?v=4","gravatar_id":"","url":"https://api.github.com/users/f97ada87","html_url":"https://github.com/f97ada87","followers_url":"https://api.github.com/users/f97ada87/followers","following_url":"https://api.github.com/users/f97ada87/following{/other_user}","gists_url":"https://api.github.com/users/f97ada87/gists{/gist_id}","starred_url":"https://api.github.com/users/f97ada87/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/f97ada87/subscriptions","organizations_url":"https://api.github.com/users/f97ada87/orgs","repos_url":"https://api.github.com/users/f97ada87/repos","events_url":"https://api.github.com/users/f97ada87/events{/privacy}","received_events_url":"https://api.github.com/users/f97ada87/received_events","type":"User","site_admin":false},"body":"done","created_at":"2018-04-16T15:41:10Z","updated_at":"2018-04-16T15:41:10Z","html_url":"https://github.com/Bitmessage/PyBitmessage/pull/1222#discussion_r181787982","pull_request_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/comments/181787982"},"html":{"href":"https://github.com/Bitmessage/PyBitmessage/pull/1222#discussion_r181787982"},"pull_request":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222"}},"in_reply_to_id":181751910},"pull_request":{"url":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222","id":181822087,"html_url":"https://github.com/Bitmessage/PyBitmessage/pull/1222","diff_url":"https://github.com/Bitmessage/PyBitmessage/pull/1222.diff","patch_url":"https://github.com/Bitmessage/PyBitmessage/pull/1222.patch","issue_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/issues/1222","number":1222,"state":"open","locked":false,"title":"implement netcat operating mode","user":{"login":"f97ada87","id":32196103,"avatar_url":"https://avatars3.githubusercontent.com/u/32196103?v=4","gravatar_id":"","url":"https://api.github.com/users/f97ada87","html_url":"https://github.com/f97ada87","followers_url":"https://api.github.com/users/f97ada87/followers","following_url":"https://api.github.com/users/f97ada87/following{/other_user}","gists_url":"https://api.github.com/users/f97ada87/gists{/gist_id}","starred_url":"https://api.github.com/users/f97ada87/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/f97ada87/subscriptions","organizations_url":"https://api.github.com/users/f97ada87/orgs","repos_url":"https://api.github.com/users/f97ada87/repos","events_url":"https://api.github.com/users/f97ada87/events{/privacy}","received_events_url":"https://api.github.com/users/f97ada87/received_events","type":"User","site_admin":false},"body":"This PR enables a special headless operating mode (which I named \"netcat\" mode due to similarities with the Unix utility) where all object processing is disabled. Instead, raw objects received from the network are output to STDOUT unprocessed, also, any valid raw objects received on STDIN are broadcast to the network. \r\n\r\nThis is a re-implementation of PR #1149 , using the switches defined in PR #1214 . The discussions from the linked PRs should provide useful background. ","created_at":"2018-04-16T10:51:17Z","updated_at":"2018-04-16T15:41:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"534f4ead0bac45ab702355244964d5ffc8f1abb6","assignee":null,"assignees":[],"requested_reviewers":[{"login":"PeterSurda","id":3815204,"avatar_url":"https://avatars0.githubusercontent.com/u/3815204?v=4","gravatar_id":"","url":"https://api.github.com/users/PeterSurda","html_url":"https://github.com/PeterSurda","followers_url":"https://api.github.com/users/PeterSurda/followers","following_url":"https://api.github.com/users/PeterSurda/following{/other_user}","gists_url":"https://api.github.com/users/PeterSurda/gists{/gist_id}","starred_url":"https://api.github.com/users/PeterSurda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PeterSurda/subscriptions","organizations_url":"https://api.github.com/users/PeterSurda/orgs","repos_url":"https://api.github.com/users/PeterSurda/repos","events_url":"https://api.github.com/users/PeterSurda/events{/privacy}","received_events_url":"https://api.github.com/users/PeterSurda/received_events","type":"User","site_admin":false},{"login":"MahendraNG","id":8371801,"avatar_url":"https://avatars1.githubusercontent.com/u/8371801?v=4","gravatar_id":"","url":"https://api.github.com/users/MahendraNG","html_url":"https://github.com/MahendraNG","followers_url":"https://api.github.com/users/MahendraNG/followers","following_url":"https://api.github.com/users/MahendraNG/following{/other_user}","gists_url":"https://api.github.com/users/MahendraNG/gists{/gist_id}","starred_url":"https://api.github.com/users/MahendraNG/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MahendraNG/subscriptions","organizations_url":"https://api.github.com/users/MahendraNG/orgs","repos_url":"https://api.github.com/users/MahendraNG/repos","events_url":"https://api.github.com/users/MahendraNG/events{/privacy}","received_events_url":"https://api.github.com/users/MahendraNG/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222/commits","review_comments_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222/comments","review_comment_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/issues/1222/comments","statuses_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/statuses/63893b53f8db0e0b107e4fd34b6684bba8d67139","head":{"label":"f97ada87:opmode-netcat-v2","ref":"opmode-netcat-v2","sha":"63893b53f8db0e0b107e4fd34b6684bba8d67139","user":{"login":"f97ada87","id":32196103,"avatar_url":"https://avatars3.githubusercontent.com/u/32196103?v=4","gravatar_id":"","url":"https://api.github.com/users/f97ada87","html_url":"https://github.com/f97ada87","followers_url":"https://api.github.com/users/f97ada87/followers","following_url":"https://api.github.com/users/f97ada87/following{/other_user}","gists_url":"https://api.github.com/users/f97ada87/gists{/gist_id}","starred_url":"https://api.github.com/users/f97ada87/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/f97ada87/subscriptions","organizations_url":"https://api.github.com/users/f97ada87/orgs","repos_url":"https://api.github.com/users/f97ada87/repos","events_url":"https://api.github.com/users/f97ada87/events{/privacy}","received_events_url":"https://api.github.com/users/f97ada87/received_events","type":"User","site_admin":false},"repo":{"id":129725392,"name":"PyBitmessage","full_name":"f97ada87/PyBitmessage","owner":{"login":"f97ada87","id":32196103,"avatar_url":"https://avatars3.githubusercontent.com/u/32196103?v=4","gravatar_id":"","url":"https://api.github.com/users/f97ada87","html_url":"https://github.com/f97ada87","followers_url":"https://api.github.com/users/f97ada87/followers","following_url":"https://api.github.com/users/f97ada87/following{/other_user}","gists_url":"https://api.github.com/users/f97ada87/gists{/gist_id}","starred_url":"https://api.github.com/users/f97ada87/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/f97ada87/subscriptions","organizations_url":"https://api.github.com/users/f97ada87/orgs","repos_url":"https://api.github.com/users/f97ada87/repos","events_url":"https://api.github.com/users/f97ada87/events{/privacy}","received_events_url":"https://api.github.com/users/f97ada87/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/f97ada87/PyBitmessage","description":"Reference client for Bitmessage: a P2P encrypted decentralised communication protocol:","fork":true,"url":"https://api.github.com/repos/f97ada87/PyBitmessage","forks_url":"https://api.github.com/repos/f97ada87/PyBitmessage/forks","keys_url":"https://api.github.com/repos/f97ada87/PyBitmessage/keys{/key_id}","collaborators_url":"https://api.github.com/repos/f97ada87/PyBitmessage/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/f97ada87/PyBitmessage/teams","hooks_url":"https://api.github.com/repos/f97ada87/PyBitmessage/hooks","issue_events_url":"https://api.github.com/repos/f97ada87/PyBitmessage/issues/events{/number}","events_url":"https://api.github.com/repos/f97ada87/PyBitmessage/events","assignees_url":"https://api.github.com/repos/f97ada87/PyBitmessage/assignees{/user}","branches_url":"https://api.github.com/repos/f97ada87/PyBitmessage/branches{/branch}","tags_url":"https://api.github.com/repos/f97ada87/PyBitmessage/tags","blobs_url":"https://api.github.com/repos/f97ada87/PyBitmessage/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/f97ada87/PyBitmessage/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/f97ada87/PyBitmessage/git/refs{/sha}","trees_url":"https://api.github.com/repos/f97ada87/PyBitmessage/git/trees{/sha}","statuses_url":"https://api.github.com/repos/f97ada87/PyBitmessage/statuses/{sha}","languages_url":"https://api.github.com/repos/f97ada87/PyBitmessage/languages","stargazers_url":"https://api.github.com/repos/f97ada87/PyBitmessage/stargazers","contributors_url":"https://api.github.com/repos/f97ada87/PyBitmessage/contributors","subscribers_url":"https://api.github.com/repos/f97ada87/PyBitmessage/subscribers","subscription_url":"https://api.github.com/repos/f97ada87/PyBitmessage/subscription","commits_url":"https://api.github.com/repos/f97ada87/PyBitmessage/commits{/sha}","git_commits_url":"https://api.github.com/repos/f97ada87/PyBitmessage/git/commits{/sha}","comments_url":"https://api.github.com/repos/f97ada87/PyBitmessage/comments{/number}","issue_comment_url":"https://api.github.com/repos/f97ada87/PyBitmessage/issues/comments{/number}","contents_url":"https://api.github.com/repos/f97ada87/PyBitmessage/contents/{+path}","compare_url":"https://api.github.com/repos/f97ada87/PyBitmessage/compare/{base}...{head}","merges_url":"https://api.github.com/repos/f97ada87/PyBitmessage/merges","archive_url":"https://api.github.com/repos/f97ada87/PyBitmessage/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/f97ada87/PyBitmessage/downloads","issues_url":"https://api.github.com/repos/f97ada87/PyBitmessage/issues{/number}","pulls_url":"https://api.github.com/repos/f97ada87/PyBitmessage/pulls{/number}","milestones_url":"https://api.github.com/repos/f97ada87/PyBitmessage/milestones{/number}","notifications_url":"https://api.github.com/repos/f97ada87/PyBitmessage/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/f97ada87/PyBitmessage/labels{/name}","releases_url":"https://api.github.com/repos/f97ada87/PyBitmessage/releases{/id}","deployments_url":"https://api.github.com/repos/f97ada87/PyBitmessage/deployments","created_at":"2018-04-16T10:24:40Z","updated_at":"2018-04-16T10:24:42Z","pushed_at":"2018-04-16T15:36:32Z","git_url":"git://github.com/f97ada87/PyBitmessage.git","ssh_url":"git@github.com:f97ada87/PyBitmessage.git","clone_url":"https://github.com/f97ada87/PyBitmessage.git","svn_url":"https://github.com/f97ada87/PyBitmessage","homepage":"https://bitmessage.org/wiki/Main_Page","size":9443,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Bitmessage:v0.6","ref":"v0.6","sha":"6a01b3d0df8251cf51d9826f773d9f799e06cf6a","user":{"login":"Bitmessage","id":2625379,"avatar_url":"https://avatars3.githubusercontent.com/u/2625379?v=4","gravatar_id":"","url":"https://api.github.com/users/Bitmessage","html_url":"https://github.com/Bitmessage","followers_url":"https://api.github.com/users/Bitmessage/followers","following_url":"https://api.github.com/users/Bitmessage/following{/other_user}","gists_url":"https://api.github.com/users/Bitmessage/gists{/gist_id}","starred_url":"https://api.github.com/users/Bitmessage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bitmessage/subscriptions","organizations_url":"https://api.github.com/users/Bitmessage/orgs","repos_url":"https://api.github.com/users/Bitmessage/repos","events_url":"https://api.github.com/users/Bitmessage/events{/privacy}","received_events_url":"https://api.github.com/users/Bitmessage/received_events","type":"Organization","site_admin":false},"repo":{"id":6648028,"name":"PyBitmessage","full_name":"Bitmessage/PyBitmessage","owner":{"login":"Bitmessage","id":2625379,"avatar_url":"https://avatars3.githubusercontent.com/u/2625379?v=4","gravatar_id":"","url":"https://api.github.com/users/Bitmessage","html_url":"https://github.com/Bitmessage","followers_url":"https://api.github.com/users/Bitmessage/followers","following_url":"https://api.github.com/users/Bitmessage/following{/other_user}","gists_url":"https://api.github.com/users/Bitmessage/gists{/gist_id}","starred_url":"https://api.github.com/users/Bitmessage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bitmessage/subscriptions","organizations_url":"https://api.github.com/users/Bitmessage/orgs","repos_url":"https://api.github.com/users/Bitmessage/repos","events_url":"https://api.github.com/users/Bitmessage/events{/privacy}","received_events_url":"https://api.github.com/users/Bitmessage/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Bitmessage/PyBitmessage","description":"Reference client for Bitmessage: a P2P encrypted decentralised communication protocol:","fork":false,"url":"https://api.github.com/repos/Bitmessage/PyBitmessage","forks_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/forks","keys_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/teams","hooks_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/hooks","issue_events_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/issues/events{/number}","events_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/events","assignees_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/assignees{/user}","branches_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/branches{/branch}","tags_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/tags","blobs_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/git/refs{/sha}","trees_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/statuses/{sha}","languages_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/languages","stargazers_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/stargazers","contributors_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/contributors","subscribers_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/subscribers","subscription_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/subscription","commits_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/commits{/sha}","git_commits_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/git/commits{/sha}","comments_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/comments{/number}","issue_comment_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/issues/comments{/number}","contents_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/contents/{+path}","compare_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/merges","archive_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/downloads","issues_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/issues{/number}","pulls_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls{/number}","milestones_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/milestones{/number}","notifications_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/labels{/name}","releases_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/releases{/id}","deployments_url":"https://api.github.com/repos/Bitmessage/PyBitmessage/deployments","created_at":"2012-11-12T03:36:43Z","updated_at":"2018-04-15T07:36:35Z","pushed_at":"2018-04-16T15:36:35Z","git_url":"git://github.com/Bitmessage/PyBitmessage.git","ssh_url":"git@github.com:Bitmessage/PyBitmessage.git","clone_url":"https://github.com/Bitmessage/PyBitmessage.git","svn_url":"https://github.com/Bitmessage/PyBitmessage","homepage":"https://bitmessage.org/wiki/Main_Page","size":9439,"stargazers_count":2232,"watchers_count":2232,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":489,"mirror_url":null,"archived":false,"open_issues_count":136,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":489,"open_issues":136,"watchers":2232,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222"},"html":{"href":"https://github.com/Bitmessage/PyBitmessage/pull/1222"},"issue":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/issues/1222"},"comments":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/issues/1222/comments"},"review_comments":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222/comments"},"review_comment":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/pulls/1222/commits"},"statuses":{"href":"https://api.github.com/repos/Bitmessage/PyBitmessage/statuses/63893b53f8db0e0b107e4fd34b6684bba8d67139"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"f97ada87"}}