{"action":"created","comment":{"url":"https://api.github.com/repos/ably/docs/pulls/comments/174531895","pull_request_review_id":103856150,"id":174531895,"diff_hunk":"@@ -0,0 +1,255 @@\n+---\n+title: \"MQTT Tutorial: Snake with Javascript\"\n+section: tutorials\n+index: 104\n+languages:\n+  - javascript\n+  - nodejs\n+---\n+\n+Ably Realtime provides support for a number of protocols with its pub/sub system, one of which is MQTT. MQTT is an open ISO standard providing a lightweight messaging protocol for small sensors and mobile devices, optimized for high-latency or unreliable networks. Whilst we reccomend use of the Ably realtime protocol where you can, MQTT can be great for use with languages we don't currently support, and when you have stringent bandwidth restrictions.\n+\n+h2. What you'll be building\n+\n+In this tutorial, you'll be using the MQTT protocol with Ably to connect a controller made in Node.js with a game of Snake in a browser. This tutorial will be doing this with the assumption that your input will be from a keyboard and will be using JavaScript to make this tutorial as simple as possible. Other than reading the inputs to your controller however it doesn't matter what the controller is or what it is programmed in, so long as MQTT is supported.\n+\n+<%= partial 'tutorials/_step-1-setup-free-account' %>\n+\n+h2. Step 2 - Set up your device\n+\n+Now that you have an Ably account and have your API Key, you can work on setting up your controller. Firstly, you'll need to create a folder and enter it. To do this type the following into your command line:\n+\n+```[sh]\n+  mkdir mqtt-snake\n+  cd mqtt-snake\n+```\n+\n+You'll also need the MQTT.js and keypress NPM modules for the controller, so type the following into your command line to get them:\n+\n+```[sh]\n+  npm install mqtt --save\n+  npm install keypress —-save\n+```\n+\n+You'll now see all the required files inside the @node_modules@ folder that has been created within the @mqtt-snake@ folder.\n+\n+\"MQTT.js\":https://www.npmjs.com/package/mqtt is required for you to use MQTT in Javascript, and \"keypress\":https://www.npmjs.com/package/keypress allows for you to easily detect keys being pressed on the keyboard.\n+\n+\"See this step in Github\":https://github.com/ably/tutorials/TODO\n+\n+h2. Step 3 - Add your libraries\n+\n+With your NPM modules ready, it's time to create a file to contain your controller code. Create a file called @controller.js@ inside your @mqtt-snake@ folder. Inside this file, instance the MQTT.js and keypress libraries:\n+\n+```[javascript]\n+  const mqtt = require('mqtt');\n+  const keypress = require('keypress');\n+```\n+\n+\"See this step in Github\":https://github.com/ably/tutorials/TODO\n+\n+h2. Step 4 - Detect key presses\n+\n+Now it's time for you to detect key presses on the keyboard. In this tutorial, you'll be needing to know when the arrow keys or return key is pressed, and then through MQTT communicate which key was pressed. You'll be detecting the key presses with the keypress NPM module. Add the below code after the library instancing in the @controller.js@ file:\n+\n+```[javascript]\n+  keypress(process.stdin);\n+\n+  process.stdin.setRawMode(true);\n+\n+  process.stdin.on('keypress', function (ch, key) {\n+    if (key) {\n+      console.log('Key clicked: ' +  key.name);\n+    }\n+  });\n+```\n+\n+There are three main things occuring in this code. The first is @keypress(process.stdin)@, which will simply cause our @process.stdin@ to emit @keypress@ events.\n+\n+Secondly is @process.stdin.setRawMode(true)@, which ensures your keyboard input is available character-by-character with no modifiers. For example, when typing ctrl-c, @process.stdin@ will output the following as a @keypress@ event: \n+\n+```\n+  { name: 'c',\n+    ctrl: true,\n+    meta: false,\n+    shift: false,\n+    sequence: '\\u0003' \n+  }\n+```\n+\n+Finlly, @process.stdin.on()@ is simply a listener for the @keypress@ event. You use it in this case to print to the console whenever a key is pressed. You can try this out for yourself by running the following line of code in the terminal:\n+\n+```[sh]\n+  node controller.js\n+```\n+\n+If all is well, you should see a message saying the key you pressed whenever you click a key.\n+\n+\"See this step in Github\":https://github.com/ably/tutorials/TODO\n+\n+h2. Step 5 - Connect to Ably through MQTT\n+\n+Now that you're able to detect key presses, it's time to start transmitting these presses through MQTT to Ably. When using MQTT with Ably, there are a few requirements with regards to your setup. You'll need to connect to 'mqtt.ably.io' on port 8883, which requires the use of SSL/TLS in your connection. If you have a device which cannot support SSL, you'll need to connect via port 1883 instead, but this will come with a number of \"restrictions\":https://support.ably.io/solution/articles/3000074906-using-the-mqtt-protocol-adapter. \n+\n+You will need to set the keep alive time to a value between 15 and 60 seconds, where 60 seconds maximises the battery life, and 15 seconds will maximise responsiveness to network issues. In this tutorial you'll be setting it to 15.\n+\n+For authentication, you'll need to either use an API Key, or token. For simplicity in this tutorial you'll be using the API Key you got in step 1. To provide the API Key, you need to provide the first half of the API Key (before the colon) as the username, and the second half of the API Key (after the colon) as the password. For example, if your API key is @A12B3C.4D:5E6F7G8H@, your username will be @A12B3C.4D@ and your password will be @5E6F7G8H@.\n+\n+Add the following code below your current code in @controller.js@, replacing 'FIRST_HALF_OF_API_KEY' and 'SECOND_HALF_OF_API_KEY' with the appropiate parts of your own API Key:\n+\n+```[javascript]\n+  var options = { keepAlive: 15,\n+    username: 'FIRST_HALF_OF_API_KEY',\n+    password: 'SECOND_HALF_OF_API_KEY',\n+    port: 8883\n+  };\n+\n+  var client = mqtt.connect('mqtts:mqtt.ably.io', options);\n+\n+  client.on('connect', function () {\n+    console.log('connected!');\n+  });\n+\n+  client.on('error', function(err){\n+    console.log(err);\n+    client.end();\n+  });\n+```\n+\n+With the above code, you set @options@ as described above, and then attempt to connect to Ably's MQTT endpoint. You specify @mqtts@ as part of the host address to specify that the connect attempt should be made with MQTT using SSL/TLS.\n+\n+Try out the code now using @node controller.js@ in the commmand line and you should see in the console that the client sucessfully connects through MQTT.\n+\n+TODO: IMAGE OF \"connected!\"\n+\n+If you have any issues with this, please check out our \"usage notes\":https://support.ably.io/solution/articles/3000074906-using-the-mqtt-protocol-adapter.\n+\n+\"See this step in Github\":https://github.com/ably/tutorials/TODO\n+\n+h2. Step 6 - Send key presses through MQTT\n+\n+Now that you have established a connection through MQTT to Ably, you can send some data through it. You need to firstly create a function to easily publish messages for the key presses you're interested in. Add the following function to the bottom of @controller.js@:\n+\n+```[javascript]\n+  function publishMessage(channel, message) {\n+    client.publish(channel, message, { qos: 1 }, function(err) {\n+      if(err) {\n+        console.log(err);\n+      }\n+    }); \n+  }\n+``` \n+\n+This function simply takes the message you wish to publish, and publishes it through MQTT using @client.publish@ into the channel specified. The setting 'qos' (Quality of Service) represents whether messages are guaranteed to be delivered 'at most once' (0), 'at least once' (1), or 'exactly once' (2). Here you'll use 'at least once', as you want to ensure our inputs are delivered, but also have as little back and forth communication between this device and the server as possible.\n+\n+Now that you have a method to publish through MQTT, you need to use it to send our key presses. Inside of the function assosciated with the @process.stdin.on('keypress')@, add the following:\n+\n+```[javascript]\n+  if (key && key.ctrl && (key.name == 'c')) {\n+    process.stdin.pause();\n+    client.end();\n+  } else if(key && (key.name == 'left')) {\n+  \tpublishMessage('input', 'left');\n+  } else if(key && (key.name == 'right')) {\n+  \tpublishMessage('input', 'right');\n+  } else if(key && (key.name == 'up')) {\n+  \tpublishMessage('input', 'up');\n+  } else if(key && (key.name == 'down')) {\n+  \tpublishMessage('input', 'down');\n+  } else if(key && (key.name == 'return')) {\n+  \tpublishMessage('input', 'return');\n+  }\n+```\n+\n+All this will do is use the @publishMessage@ function you created to send the key presses you're interested in. In the case that the user types ctrl-c, the stream will be paused and the client closed so that the program can stop. Otherwise, you're sending the key pressed to the channel @input@.\n+\n+\"See this step in Github\":https://github.com/ably/tutorials/TODO\n+\n+h2. Step 7 - Recieving inputs from Ably\n+\n+Now that you've set up your controller, it's time to create something to run the game of Snake, and receive the data from Ably that you sent from the controller. You'll be using the normal Ably Realtime protocol for this part. This is possible due to the fact Ably is \"Protocol Agnostic\":https://support.ably.io/solution/articles/3000054126-do-you-support-mqtt-are-you-protocol-agnostic-, allowing for protocols to be used interchangebly.\n+\n+Firstly create a file called @snake.html@, and place the following code inside:\n+\n+```[html]\n+  <!doctype html>\n+  <html>\n+    <head>\n+      <title>Ably Realtime Snake</title>\n+      <meta name=\"description\" content=\"Fun Snake Game by Ably\">\n+      <meta name=\"keywords\" content=\"ably realtime snake\">\n+      <link rel=\"stylesheet\" href=\"game.css\">\n+      <script src=\"http://cdn.ably.io/lib/ably.min-1.js\"></script>\n+    </head>\n+    <body>\n+      <script src=\"snake.js\"></script>\n+      <h1 id=\"heading\">Ably Realtime Snake</h1>\n+      <canvas id=\"gc\" height=\"400\" width=\"400\"></canvas>\n+      </table>\n+    </body>\n+  </html>\n+```\n+\n+Next, create another file called @snake.css@ containing the following:\n+\n+```[css]\n+#heading {\n+\tcolor: #FFA500;\n+\ttext-align: center;\n+}\n+\n+#gc {\n+    padding-left: 0;\n+    padding-right: 0;\n+    margin-left: auto;\n+    margin-right: auto;\n+    display: block;\n+    width: \"400\";\n+    height: \"400\";\n+}\n+```\n+\n+Now, create a file called @snake.js@, and put in the following code, replacing REPLACE_WITH_YOUR_API_KEY with your API Key:\n+\n+```[javascript]\n+  var ably = new Ably.Realtime('REPLACE_WITH_YOUR_API_KEY');\n+  var enc = new TextDecoder();\n+  var channel = ably.channels.get('input');\n+  channel.subscribe(function(message) {\n+    var command = enc.decode(message.data);\n+    console.log(command);\n+  });\n+```\n+\n+This will simply subscribe to the @input@ channel you're publishing to from the controller, and print it into the console. Open up @snake.html@ in a browser, open up the browser's \"console\":http://wickedlysmart.com/hfjsconsole/, and run your controller by typing @node controller.js@ into your command line. Now when you press the arrow keys from your controller, you should see messages being received by the browser in the console.\n+\n+TODO: Add image of controller input + console output\n+\n+\"See this step in Github\":https://github.com/ably/tutorials/TODO\n+\n+h2. Step 8 - Play Snake!\n+\n+With the setup complete, you can now add in the code for the actual snake game. Replace the contents of @snake.js@ with \"this\":https://github.com/ably/tutorials/TODO code, replacing REPLACE_WITH_YOUR_API_KEY with your API Key, and when you reload the @snake.html@ page you should see your basic Snake game. Run the controller as before, and you can now play! Press enter to start, arrow keys to move, and try to grow as large as you can.\n+\n+TODO: GIF of Snake being played\n+\n+The complete source code for each step of \"this tutorial is available on Github\":https://github.com/ably/tutorials/commits/TODO.\n+\n+We recommend that you clone the repo locally:\n+\n+bc[sh]. git clone https://github.com/ably/tutorials.git\n+\n+Checkout the tutorial branch:","path":"content/tutorials/MQTT-snake-js.textile","position":253,"original_position":242,"commit_id":"24d7a3527ceea35201bcfd7ad7ce7e0a7e75fb39","original_commit_id":"248e4011ec6685f3ca5446953f319e82e920b9b3","user":{"login":"Srushtika","id":5900152,"avatar_url":"https://avatars0.githubusercontent.com/u/5900152?v=4","gravatar_id":"","url":"https://api.github.com/users/Srushtika","html_url":"https://github.com/Srushtika","followers_url":"https://api.github.com/users/Srushtika/followers","following_url":"https://api.github.com/users/Srushtika/following{/other_user}","gists_url":"https://api.github.com/users/Srushtika/gists{/gist_id}","starred_url":"https://api.github.com/users/Srushtika/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Srushtika/subscriptions","organizations_url":"https://api.github.com/users/Srushtika/orgs","repos_url":"https://api.github.com/users/Srushtika/repos","events_url":"https://api.github.com/users/Srushtika/events{/privacy}","received_events_url":"https://api.github.com/users/Srushtika/received_events","type":"User","site_admin":false},"body":"Checkout to* the tutorial branch","created_at":"2018-03-14T16:53:29Z","updated_at":"2018-03-14T16:57:17Z","html_url":"https://github.com/ably/docs/pull/402#discussion_r174531895","pull_request_url":"https://api.github.com/repos/ably/docs/pulls/402","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/ably/docs/pulls/comments/174531895"},"html":{"href":"https://github.com/ably/docs/pull/402#discussion_r174531895"},"pull_request":{"href":"https://api.github.com/repos/ably/docs/pulls/402"}}},"pull_request":{"url":"https://api.github.com/repos/ably/docs/pulls/402","id":174945660,"html_url":"https://github.com/ably/docs/pull/402","diff_url":"https://github.com/ably/docs/pull/402.diff","patch_url":"https://github.com/ably/docs/pull/402.patch","issue_url":"https://api.github.com/repos/ably/docs/issues/402","number":402,"state":"open","locked":false,"title":"MQTT snake tutorial","user":{"login":"tomczoink","id":9784119,"avatar_url":"https://avatars1.githubusercontent.com/u/9784119?v=4","gravatar_id":"","url":"https://api.github.com/users/tomczoink","html_url":"https://github.com/tomczoink","followers_url":"https://api.github.com/users/tomczoink/followers","following_url":"https://api.github.com/users/tomczoink/following{/other_user}","gists_url":"https://api.github.com/users/tomczoink/gists{/gist_id}","starred_url":"https://api.github.com/users/tomczoink/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomczoink/subscriptions","organizations_url":"https://api.github.com/users/tomczoink/orgs","repos_url":"https://api.github.com/users/tomczoink/repos","events_url":"https://api.github.com/users/tomczoink/events{/privacy}","received_events_url":"https://api.github.com/users/tomczoink/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-03-14T12:54:15Z","updated_at":"2018-03-14T16:57:17Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c81df07c1b63d6cdb1ae6d5ff93408f39a085e28","assignee":null,"assignees":[],"requested_reviewers":[{"login":"mattheworiordan","id":43789,"avatar_url":"https://avatars3.githubusercontent.com/u/43789?v=4","gravatar_id":"","url":"https://api.github.com/users/mattheworiordan","html_url":"https://github.com/mattheworiordan","followers_url":"https://api.github.com/users/mattheworiordan/followers","following_url":"https://api.github.com/users/mattheworiordan/following{/other_user}","gists_url":"https://api.github.com/users/mattheworiordan/gists{/gist_id}","starred_url":"https://api.github.com/users/mattheworiordan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mattheworiordan/subscriptions","organizations_url":"https://api.github.com/users/mattheworiordan/orgs","repos_url":"https://api.github.com/users/mattheworiordan/repos","events_url":"https://api.github.com/users/mattheworiordan/events{/privacy}","received_events_url":"https://api.github.com/users/mattheworiordan/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":827772816,"url":"https://api.github.com/repos/ably/docs/labels/tutorial","name":"tutorial","color":"abfcb3","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/ably/docs/pulls/402/commits","review_comments_url":"https://api.github.com/repos/ably/docs/pulls/402/comments","review_comment_url":"https://api.github.com/repos/ably/docs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ably/docs/issues/402/comments","statuses_url":"https://api.github.com/repos/ably/docs/statuses/24d7a3527ceea35201bcfd7ad7ce7e0a7e75fb39","head":{"label":"ably:mqtt-snake-tutorial","ref":"mqtt-snake-tutorial","sha":"24d7a3527ceea35201bcfd7ad7ce7e0a7e75fb39","user":{"login":"ably","id":1859245,"avatar_url":"https://avatars0.githubusercontent.com/u/1859245?v=4","gravatar_id":"","url":"https://api.github.com/users/ably","html_url":"https://github.com/ably","followers_url":"https://api.github.com/users/ably/followers","following_url":"https://api.github.com/users/ably/following{/other_user}","gists_url":"https://api.github.com/users/ably/gists{/gist_id}","starred_url":"https://api.github.com/users/ably/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ably/subscriptions","organizations_url":"https://api.github.com/users/ably/orgs","repos_url":"https://api.github.com/users/ably/repos","events_url":"https://api.github.com/users/ably/events{/privacy}","received_events_url":"https://api.github.com/users/ably/received_events","type":"Organization","site_admin":false},"repo":{"id":7221949,"name":"docs","full_name":"ably/docs","owner":{"login":"ably","id":1859245,"avatar_url":"https://avatars0.githubusercontent.com/u/1859245?v=4","gravatar_id":"","url":"https://api.github.com/users/ably","html_url":"https://github.com/ably","followers_url":"https://api.github.com/users/ably/followers","following_url":"https://api.github.com/users/ably/following{/other_user}","gists_url":"https://api.github.com/users/ably/gists{/gist_id}","starred_url":"https://api.github.com/users/ably/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ably/subscriptions","organizations_url":"https://api.github.com/users/ably/orgs","repos_url":"https://api.github.com/users/ably/repos","events_url":"https://api.github.com/users/ably/events{/privacy}","received_events_url":"https://api.github.com/users/ably/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ably/docs","description":"Ably API documentation ","fork":false,"url":"https://api.github.com/repos/ably/docs","forks_url":"https://api.github.com/repos/ably/docs/forks","keys_url":"https://api.github.com/repos/ably/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ably/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ably/docs/teams","hooks_url":"https://api.github.com/repos/ably/docs/hooks","issue_events_url":"https://api.github.com/repos/ably/docs/issues/events{/number}","events_url":"https://api.github.com/repos/ably/docs/events","assignees_url":"https://api.github.com/repos/ably/docs/assignees{/user}","branches_url":"https://api.github.com/repos/ably/docs/branches{/branch}","tags_url":"https://api.github.com/repos/ably/docs/tags","blobs_url":"https://api.github.com/repos/ably/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ably/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ably/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/ably/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ably/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/ably/docs/languages","stargazers_url":"https://api.github.com/repos/ably/docs/stargazers","contributors_url":"https://api.github.com/repos/ably/docs/contributors","subscribers_url":"https://api.github.com/repos/ably/docs/subscribers","subscription_url":"https://api.github.com/repos/ably/docs/subscription","commits_url":"https://api.github.com/repos/ably/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/ably/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/ably/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/ably/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/ably/docs/contents/{+path}","compare_url":"https://api.github.com/repos/ably/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ably/docs/merges","archive_url":"https://api.github.com/repos/ably/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ably/docs/downloads","issues_url":"https://api.github.com/repos/ably/docs/issues{/number}","pulls_url":"https://api.github.com/repos/ably/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/ably/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/ably/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ably/docs/labels{/name}","releases_url":"https://api.github.com/repos/ably/docs/releases{/id}","deployments_url":"https://api.github.com/repos/ably/docs/deployments","created_at":"2012-12-18T10:59:49Z","updated_at":"2017-06-08T19:11:33Z","pushed_at":"2018-03-14T12:54:16Z","git_url":"git://github.com/ably/docs.git","ssh_url":"git@github.com:ably/docs.git","clone_url":"https://github.com/ably/docs.git","svn_url":"https://github.com/ably/docs","homepage":"https://www.ably.io/documentation","size":16597,"stargazers_count":3,"watchers_count":3,"language":"Ruby","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"archived":false,"open_issues_count":96,"license":null,"forks":16,"open_issues":96,"watchers":3,"default_branch":"master"}},"base":{"label":"ably:master","ref":"master","sha":"7daf2b15011c800e1fd23f2f2652572119245248","user":{"login":"ably","id":1859245,"avatar_url":"https://avatars0.githubusercontent.com/u/1859245?v=4","gravatar_id":"","url":"https://api.github.com/users/ably","html_url":"https://github.com/ably","followers_url":"https://api.github.com/users/ably/followers","following_url":"https://api.github.com/users/ably/following{/other_user}","gists_url":"https://api.github.com/users/ably/gists{/gist_id}","starred_url":"https://api.github.com/users/ably/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ably/subscriptions","organizations_url":"https://api.github.com/users/ably/orgs","repos_url":"https://api.github.com/users/ably/repos","events_url":"https://api.github.com/users/ably/events{/privacy}","received_events_url":"https://api.github.com/users/ably/received_events","type":"Organization","site_admin":false},"repo":{"id":7221949,"name":"docs","full_name":"ably/docs","owner":{"login":"ably","id":1859245,"avatar_url":"https://avatars0.githubusercontent.com/u/1859245?v=4","gravatar_id":"","url":"https://api.github.com/users/ably","html_url":"https://github.com/ably","followers_url":"https://api.github.com/users/ably/followers","following_url":"https://api.github.com/users/ably/following{/other_user}","gists_url":"https://api.github.com/users/ably/gists{/gist_id}","starred_url":"https://api.github.com/users/ably/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ably/subscriptions","organizations_url":"https://api.github.com/users/ably/orgs","repos_url":"https://api.github.com/users/ably/repos","events_url":"https://api.github.com/users/ably/events{/privacy}","received_events_url":"https://api.github.com/users/ably/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ably/docs","description":"Ably API documentation ","fork":false,"url":"https://api.github.com/repos/ably/docs","forks_url":"https://api.github.com/repos/ably/docs/forks","keys_url":"https://api.github.com/repos/ably/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ably/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ably/docs/teams","hooks_url":"https://api.github.com/repos/ably/docs/hooks","issue_events_url":"https://api.github.com/repos/ably/docs/issues/events{/number}","events_url":"https://api.github.com/repos/ably/docs/events","assignees_url":"https://api.github.com/repos/ably/docs/assignees{/user}","branches_url":"https://api.github.com/repos/ably/docs/branches{/branch}","tags_url":"https://api.github.com/repos/ably/docs/tags","blobs_url":"https://api.github.com/repos/ably/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ably/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ably/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/ably/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ably/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/ably/docs/languages","stargazers_url":"https://api.github.com/repos/ably/docs/stargazers","contributors_url":"https://api.github.com/repos/ably/docs/contributors","subscribers_url":"https://api.github.com/repos/ably/docs/subscribers","subscription_url":"https://api.github.com/repos/ably/docs/subscription","commits_url":"https://api.github.com/repos/ably/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/ably/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/ably/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/ably/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/ably/docs/contents/{+path}","compare_url":"https://api.github.com/repos/ably/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ably/docs/merges","archive_url":"https://api.github.com/repos/ably/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ably/docs/downloads","issues_url":"https://api.github.com/repos/ably/docs/issues{/number}","pulls_url":"https://api.github.com/repos/ably/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/ably/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/ably/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ably/docs/labels{/name}","releases_url":"https://api.github.com/repos/ably/docs/releases{/id}","deployments_url":"https://api.github.com/repos/ably/docs/deployments","created_at":"2012-12-18T10:59:49Z","updated_at":"2017-06-08T19:11:33Z","pushed_at":"2018-03-14T12:54:16Z","git_url":"git://github.com/ably/docs.git","ssh_url":"git@github.com:ably/docs.git","clone_url":"https://github.com/ably/docs.git","svn_url":"https://github.com/ably/docs","homepage":"https://www.ably.io/documentation","size":16597,"stargazers_count":3,"watchers_count":3,"language":"Ruby","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"archived":false,"open_issues_count":96,"license":null,"forks":16,"open_issues":96,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ably/docs/pulls/402"},"html":{"href":"https://github.com/ably/docs/pull/402"},"issue":{"href":"https://api.github.com/repos/ably/docs/issues/402"},"comments":{"href":"https://api.github.com/repos/ably/docs/issues/402/comments"},"review_comments":{"href":"https://api.github.com/repos/ably/docs/pulls/402/comments"},"review_comment":{"href":"https://api.github.com/repos/ably/docs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ably/docs/pulls/402/commits"},"statuses":{"href":"https://api.github.com/repos/ably/docs/statuses/24d7a3527ceea35201bcfd7ad7ce7e0a7e75fb39"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"Srushtika"}}