{"action":"created","comment":{"url":"https://api.github.com/repos/syncthing/docs/pulls/comments/43707250","id":43707250,"diff_hunk":"@@ -0,0 +1,410 @@\n+.. _relay-v1:\r\n+\r\n+Relay Protocol v1\r\n+=================\r\n+\r\n+What is a relay?\r\n+----------------\r\n+\r\n+Relay is a service which relays data between two *devices* which are not able to\r\n+connect to each other directly otherwise. This is usually due to both devices\r\n+being behind a NAT and neither sides not being able to open a port which would\r\n+be directly accessible from the internet.\r\n+\r\n+A relay was designed to relay BEP protocol, hence the reliance on device ID's\r\n+in the protocol spec, but at the same time it is general enough that could be\r\n+reused by other protocols or aplications, as the data transfered between two\r\n+devices which use a relay is completely obscure and does not affect the\r\n+relaying.\r\n+\r\n+Operation modes\r\n+---------------\r\n+\r\n+Relay listens on a single TCP socket, but has two different connection modes,\r\n+where a connection mode is a predefined set of messages which the relay and\r\n+the device are expecting to exchange.\r\n+\r\n+The first mode is the `protocol` mode which allows a client to interact\r\n+with the relay, for example join the relay, or request to connect to a device,\r\n+given it is available on the relay. Simillarly to BEP, protocol mode requires\r\n+the device to connect via TLS using a strong suite of ciphers (same as BEP),\r\n+which allows the relay to verify and derive the identity (Device ID) of the\r\n+device.\r\n+\r\n+The second mode is the `session` mode which after a few initial messages\r\n+connects two devices directly to each other via the relay, and is a plain-text\r\n+protocol, which for every byte written by one device, sends the same set of\r\n+bytes to the other device and vica versa.\r\n+\r\n+Identifying the connection mode\r\n+-------------------------------\r\n+\r\n+Because both connection modes operate over the same single socket, a method\r\n+of detecting the connection mode is required.\r\n+\r\n+When a new client connects to the relay, the relay checks the first byte\r\n+that the client has sent, and if that matches 0x16, that implies to us that\r\n+the connection is a protocol mode connection, due to 0x16 being the first byte\r\n+in the TLS handshake, and only protocol mode connections use TLS.\r\n+\r\n+If the first byte is not 0x16, then we assume that the connection is a session\r\n+mode connection.\r\n+\r\n+Protocol mode\r\n+-------------\r\n+\r\n+Protocol mode uses TLS, and protocol name defined by the TLS heander should be\r\n+`bep-relay`.\r\n+\r\n+Protocol mode has two submodes:\r\n+1. Permanent protocol submode - Joining the relay, and waiting for messages from\r\n+the relay asking to connect to some device which is interested in having a\r\n+session with you.\r\n+2. Temporary protocol submode - Only used to request a session with a device\r\n+which is connected to the relay using the permanent protocol submode.\r\n+\r\n+\r\n+Permanent protocol submode\r\n+~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+A permanent protocol submode begins with the client sending a JoinRelayRequest\r\n+message, which the relay responds to with either a ResponseSuccess or\r\n+ResponseAlreadyConnected message if a client with the same device ID already\r\n+exists.\r\n+\r\n+After the client has joined, no more messages are exchanged apart from\r\n+Ping/Pong messages for general connection keep alive checking.\r\n+\r\n+From this point onwards, the client stand-by's and waits for SessionInvitation\r\n+messages from the relay, which implies that some other device is trying to\r\n+connect with you. SessionInvitation message contains the unique session key\r\n+which then can be used to establish a connection in session mode.\r\n+\r\n+If the client fails to send a JoinRelayRequest message within the first ping\r\n+interval, the connection is terminated.\r\n+If the client fails to send a message (even if its a ping message) every minute\r\n+(by default), the connection is terminated.\r\n+\r\n+Temporary protocol submode\r\n+~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+A temporary protocol submode begins with ConnectRequest message, to which the\r\n+relay responds with either ResponseNotFound if the device the client it is after\r\n+is not available, or with a SessionInvitation, which contains the unique session\r\n+key which then can be used to establish a connection in session mode.\r\n+\r\n+The connection is terminated immediately after that.\r\n+\r\n+Example Exchange\r\n+~~~~~~~~~~~~~~~~\r\n+\r\n+Client A - Permanent protocol submode\r\n+Client B - Temporary protocol submode\r\n+\r\n+===  =======================  ====================== =====================\r\n+ #         Client (A)                 Relay                Client (B)\r\n+===  =======================  ====================== =====================\r\n+ 1   JoinRelayRequest->\r\n+ 2                            <-ResponseSuccess\r\n+ 3   Ping->\r\n+ 4                            <-Pong\r\n+ 5                                                    <-ConnectRequest(A)\r\n+ 6                            SessionInvitation(A)->\r\n+ 7                            <-SessionInvitation(B)\r\n+ 8                                                    (Disconnects)\r\n+ 9   Ping->\r\n+ 10                           <-Pong\r\n+ 11  Ping->\r\n+ 12                           <-Pong\r\n+===  =======================  ====================== =====================\r\n+\r\n+\r\n+Session mode\r\n+------------\r\n+\r\n+The first and only message the client sends in the session mode is the\r\n+SessionInvitation message which contains the session key identifying which\r\n+session you are trying to join.\r\n+.. The relay responds with one of the following Response messages:\r\n+   1. ResponseNotFound - Session key is invalid\r\n+   2. ResponseAlreadyConnected - Session is full (both sides already connected)\r\n+   3. ResponseSuccess - You have successfully joined the session\r\n+\r\n+After the successful response, all the bytes written and received will be\r\n+relayed between the two devices in the session directly.\r\n+\r\n+Example Exchange\r\n+~~~~~~~~~~~~~~~~\r\n+\r\n+Client A - Permanent protocol mode\r\n+Client B - Temporary protocol mode\r\n+\r\n+===  =======================  ====================== =====================\r\n+ #         Client (A)                 Relay                Client (B)\r\n+===  =======================  ====================== =====================\r\n+ 1   SessionInvitation(A)->\r\n+ 2                            <-ResponseSuccess\r\n+ 3   Data->                   (Buffers data)\r\n+ 4   Data->                   (Buffers data)\r\n+ 5                                                   <-SessionInvitation(B)\r\n+ 6                            ResponseSuccess->\r\n+ 7                            Relays data ->\r\n+ 8                            Relays data ->\r\n+ 9                            <-Relays data          <-Data\r\n+===  =======================  ====================== =====================\r\n+\r\n+Messages\r\n+--------\r\n+\r\n+All messages are preceeded by a header message. Header message contains the\r\n+magic value 0x9E79BC40, message type integer, and message length.\r\n+\r\n+\r\n+Header structure\r\n+~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                             Magic                             |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                         Message Type                          |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                        Message Length                         |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct Header {\r\n+\t\tunsigned int Magic;\r\n+\t\tint MessageType;\r\n+\t\tint MessageLength;\r\n+\t}\r\n+\r\n+Ping message (Type = 0)\r\n+~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct Ping {\r\n+\t}\r\n+\r\n+Pong message (Type = 1)\r\n+~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct Pong {\r\n+\t}\r\n+\r\n+JoinRelayRequest message (Type = 2)\r\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct JoinRelayRequest {\r\n+\t}\r\n+\r\n+JoinSessionRequest message (Type = 3)\r\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                         Length of Key                         |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t/                                                               /\r\n+\t\\                     Key (variable length)                     \\\r\n+\t/                                                               /\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct JoinSessionRequest {\r\n+\t\topaque Key<32>;\r\n+\t}\r\n+\r\n+: Key\r\n+\tThis is a unique random session key generated by the relay server. It's is\r\n+\tused to identify which session you are trying to connect to.\r\n+\r\n+\r\n+Response message (Type = 4)\r\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                             Code                              |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                       Length of Message                       |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t/                                                               /\r\n+\t\\                   Message (variable length)                   \\\r\n+\t/                                                               /\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct Response {\r\n+\t\tint Code;\r\n+\t\tstring Message<>;\r\n+\t}\r\n+\r\n+: Code\r\n+\tAn integer representing the status code.\r\n+: Message\r\n+\tMessage associated with the code.\r\n+\r\n+.. Protocol defined responses:\r\n+\t1. ResponseSuccess           = Response{0, \"success\"}\r\n+\t2 .ResponseNotFound          = Response{1, \"not found\"}\r\n+\t3. ResponseAlreadyConnected  = Response{2, \"already connected\"}\r\n+\t4. ResponseInternalError     = Response{99, \"internal error\"}\r\n+\t5. ResponseUnexpectedMessage = Response{100, \"unexpected message\"}\r\n+\r\n+ConnectRequest message (Type = 5)\r\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                         Length of ID                          |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t/                                                               /\r\n+\t\\                     ID (variable length)                      \\\r\n+\t/                                                               /\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct ConnectRequest {\r\n+\t\topaque ID<32>;\r\n+\t}\r\n+\r\n+: ID\r\n+\tDevice ID to which the client would like to connect.\r\n+\r\n+\r\n+SessionInvitation message (Type = 6)\r\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n+\r\n+::\r\n+\r\n+\t 0                   1                   2                   3\r\n+\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                        Length of From                         |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t/                                                               /\r\n+\t\\                    From (variable length)                     \\\r\n+\t/                                                               /\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                         Length of Key                         |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t/                                                               /\r\n+\t\\                     Key (variable length)                     \\\r\n+\t/                                                               /\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                       Length of Address                       |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t/                                                               /\r\n+\t\\                   Address (variable length)                   \\\r\n+\t/                                                               /\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|            0x0000             |             Port              |\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\t|                  Server Socket (V=0 or 1)                   |V|\r\n+\t+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n+\r\n+\r\n+\tstruct SessionInvitation {\r\n+\t\topaque From<32>;\r\n+\t\topaque Key<32>;\r\n+\t\topaque Address<32>;\r\n+\t\tunsigned int Port;\r\n+\t\tbool ServerSocket;\r\n+\t}\r\n+\r\n+: From\r\n+\tDevice ID identifying who you will be connecting with.\r\n+: Key\r\n+\tA unique random session key generated by the relay server. It's is used to\r","path":"specs/relay-v1.rst","position":351,"original_position":351,"commit_id":"78f154577f6b6454040b4a6a1734924c353355a4","original_commit_id":"78f154577f6b6454040b4a6a1734924c353355a4","user":{"login":"phil-davis","id":1535615,"avatar_url":"https://avatars.githubusercontent.com/u/1535615?v=3","gravatar_id":"","url":"https://api.github.com/users/phil-davis","html_url":"https://github.com/phil-davis","followers_url":"https://api.github.com/users/phil-davis/followers","following_url":"https://api.github.com/users/phil-davis/following{/other_user}","gists_url":"https://api.github.com/users/phil-davis/gists{/gist_id}","starred_url":"https://api.github.com/users/phil-davis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/phil-davis/subscriptions","organizations_url":"https://api.github.com/users/phil-davis/orgs","repos_url":"https://api.github.com/users/phil-davis/repos","events_url":"https://api.github.com/users/phil-davis/events{/privacy}","received_events_url":"https://api.github.com/users/phil-davis/received_events","type":"User","site_admin":false},"body":"\"It's is\" => \"It is\"","created_at":"2015-11-03T01:21:06Z","updated_at":"2015-11-03T01:21:06Z","html_url":"https://github.com/syncthing/docs/pull/67#discussion_r43707250","pull_request_url":"https://api.github.com/repos/syncthing/docs/pulls/67","_links":{"self":{"href":"https://api.github.com/repos/syncthing/docs/pulls/comments/43707250"},"html":{"href":"https://github.com/syncthing/docs/pull/67#discussion_r43707250"},"pull_request":{"href":"https://api.github.com/repos/syncthing/docs/pulls/67"}}},"pull_request":{"url":"https://api.github.com/repos/syncthing/docs/pulls/67","id":49487446,"html_url":"https://github.com/syncthing/docs/pull/67","diff_url":"https://github.com/syncthing/docs/pull/67.diff","patch_url":"https://github.com/syncthing/docs/pull/67.patch","issue_url":"https://api.github.com/repos/syncthing/docs/issues/67","number":67,"state":"open","locked":false,"title":"Add relay protocol definition","user":{"login":"AudriusButkevicius","id":1144861,"avatar_url":"https://avatars.githubusercontent.com/u/1144861?v=3","gravatar_id":"","url":"https://api.github.com/users/AudriusButkevicius","html_url":"https://github.com/AudriusButkevicius","followers_url":"https://api.github.com/users/AudriusButkevicius/followers","following_url":"https://api.github.com/users/AudriusButkevicius/following{/other_user}","gists_url":"https://api.github.com/users/AudriusButkevicius/gists{/gist_id}","starred_url":"https://api.github.com/users/AudriusButkevicius/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AudriusButkevicius/subscriptions","organizations_url":"https://api.github.com/users/AudriusButkevicius/orgs","repos_url":"https://api.github.com/users/AudriusButkevicius/repos","events_url":"https://api.github.com/users/AudriusButkevicius/events{/privacy}","received_events_url":"https://api.github.com/users/AudriusButkevicius/received_events","type":"User","site_admin":false},"body":"For proof reading and suggestions","created_at":"2015-11-02T21:23:12Z","updated_at":"2015-11-03T01:21:06Z","closed_at":null,"merged_at":null,"merge_commit_sha":"939f74b64b7db7438887ecc4138db3489b3e2e1f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/syncthing/docs/pulls/67/commits","review_comments_url":"https://api.github.com/repos/syncthing/docs/pulls/67/comments","review_comment_url":"https://api.github.com/repos/syncthing/docs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/syncthing/docs/issues/67/comments","statuses_url":"https://api.github.com/repos/syncthing/docs/statuses/78f154577f6b6454040b4a6a1734924c353355a4","head":{"label":"AudriusButkevicius:relay","ref":"relay","sha":"78f154577f6b6454040b4a6a1734924c353355a4","user":{"login":"AudriusButkevicius","id":1144861,"avatar_url":"https://avatars.githubusercontent.com/u/1144861?v=3","gravatar_id":"","url":"https://api.github.com/users/AudriusButkevicius","html_url":"https://github.com/AudriusButkevicius","followers_url":"https://api.github.com/users/AudriusButkevicius/followers","following_url":"https://api.github.com/users/AudriusButkevicius/following{/other_user}","gists_url":"https://api.github.com/users/AudriusButkevicius/gists{/gist_id}","starred_url":"https://api.github.com/users/AudriusButkevicius/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AudriusButkevicius/subscriptions","organizations_url":"https://api.github.com/users/AudriusButkevicius/orgs","repos_url":"https://api.github.com/users/AudriusButkevicius/repos","events_url":"https://api.github.com/users/AudriusButkevicius/events{/privacy}","received_events_url":"https://api.github.com/users/AudriusButkevicius/received_events","type":"User","site_admin":false},"repo":{"id":37251064,"name":"docs","full_name":"AudriusButkevicius/docs","owner":{"login":"AudriusButkevicius","id":1144861,"avatar_url":"https://avatars.githubusercontent.com/u/1144861?v=3","gravatar_id":"","url":"https://api.github.com/users/AudriusButkevicius","html_url":"https://github.com/AudriusButkevicius","followers_url":"https://api.github.com/users/AudriusButkevicius/followers","following_url":"https://api.github.com/users/AudriusButkevicius/following{/other_user}","gists_url":"https://api.github.com/users/AudriusButkevicius/gists{/gist_id}","starred_url":"https://api.github.com/users/AudriusButkevicius/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AudriusButkevicius/subscriptions","organizations_url":"https://api.github.com/users/AudriusButkevicius/orgs","repos_url":"https://api.github.com/users/AudriusButkevicius/repos","events_url":"https://api.github.com/users/AudriusButkevicius/events{/privacy}","received_events_url":"https://api.github.com/users/AudriusButkevicius/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AudriusButkevicius/docs","description":"Documentation site","fork":true,"url":"https://api.github.com/repos/AudriusButkevicius/docs","forks_url":"https://api.github.com/repos/AudriusButkevicius/docs/forks","keys_url":"https://api.github.com/repos/AudriusButkevicius/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AudriusButkevicius/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AudriusButkevicius/docs/teams","hooks_url":"https://api.github.com/repos/AudriusButkevicius/docs/hooks","issue_events_url":"https://api.github.com/repos/AudriusButkevicius/docs/issues/events{/number}","events_url":"https://api.github.com/repos/AudriusButkevicius/docs/events","assignees_url":"https://api.github.com/repos/AudriusButkevicius/docs/assignees{/user}","branches_url":"https://api.github.com/repos/AudriusButkevicius/docs/branches{/branch}","tags_url":"https://api.github.com/repos/AudriusButkevicius/docs/tags","blobs_url":"https://api.github.com/repos/AudriusButkevicius/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AudriusButkevicius/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AudriusButkevicius/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/AudriusButkevicius/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AudriusButkevicius/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/AudriusButkevicius/docs/languages","stargazers_url":"https://api.github.com/repos/AudriusButkevicius/docs/stargazers","contributors_url":"https://api.github.com/repos/AudriusButkevicius/docs/contributors","subscribers_url":"https://api.github.com/repos/AudriusButkevicius/docs/subscribers","subscription_url":"https://api.github.com/repos/AudriusButkevicius/docs/subscription","commits_url":"https://api.github.com/repos/AudriusButkevicius/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/AudriusButkevicius/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/AudriusButkevicius/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/AudriusButkevicius/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/AudriusButkevicius/docs/contents/{+path}","compare_url":"https://api.github.com/repos/AudriusButkevicius/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AudriusButkevicius/docs/merges","archive_url":"https://api.github.com/repos/AudriusButkevicius/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AudriusButkevicius/docs/downloads","issues_url":"https://api.github.com/repos/AudriusButkevicius/docs/issues{/number}","pulls_url":"https://api.github.com/repos/AudriusButkevicius/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/AudriusButkevicius/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/AudriusButkevicius/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AudriusButkevicius/docs/labels{/name}","releases_url":"https://api.github.com/repos/AudriusButkevicius/docs/releases{/id}","created_at":"2015-06-11T09:12:11Z","updated_at":"2015-06-11T09:12:12Z","pushed_at":"2015-11-02T21:26:09Z","git_url":"git://github.com/AudriusButkevicius/docs.git","ssh_url":"git@github.com:AudriusButkevicius/docs.git","clone_url":"https://github.com/AudriusButkevicius/docs.git","svn_url":"https://github.com/AudriusButkevicius/docs","homepage":"http://docs.syncthing.net/","size":2709,"stargazers_count":0,"watchers_count":0,"language":"CSS","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":"syncthing:master","ref":"master","sha":"3324a3f4e6233f557591dd33c6f3a78d65f2626d","user":{"login":"syncthing","id":7628018,"avatar_url":"https://avatars.githubusercontent.com/u/7628018?v=3","gravatar_id":"","url":"https://api.github.com/users/syncthing","html_url":"https://github.com/syncthing","followers_url":"https://api.github.com/users/syncthing/followers","following_url":"https://api.github.com/users/syncthing/following{/other_user}","gists_url":"https://api.github.com/users/syncthing/gists{/gist_id}","starred_url":"https://api.github.com/users/syncthing/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/syncthing/subscriptions","organizations_url":"https://api.github.com/users/syncthing/orgs","repos_url":"https://api.github.com/users/syncthing/repos","events_url":"https://api.github.com/users/syncthing/events{/privacy}","received_events_url":"https://api.github.com/users/syncthing/received_events","type":"Organization","site_admin":false},"repo":{"id":36279832,"name":"docs","full_name":"syncthing/docs","owner":{"login":"syncthing","id":7628018,"avatar_url":"https://avatars.githubusercontent.com/u/7628018?v=3","gravatar_id":"","url":"https://api.github.com/users/syncthing","html_url":"https://github.com/syncthing","followers_url":"https://api.github.com/users/syncthing/followers","following_url":"https://api.github.com/users/syncthing/following{/other_user}","gists_url":"https://api.github.com/users/syncthing/gists{/gist_id}","starred_url":"https://api.github.com/users/syncthing/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/syncthing/subscriptions","organizations_url":"https://api.github.com/users/syncthing/orgs","repos_url":"https://api.github.com/users/syncthing/repos","events_url":"https://api.github.com/users/syncthing/events{/privacy}","received_events_url":"https://api.github.com/users/syncthing/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/syncthing/docs","description":"Documentation site","fork":false,"url":"https://api.github.com/repos/syncthing/docs","forks_url":"https://api.github.com/repos/syncthing/docs/forks","keys_url":"https://api.github.com/repos/syncthing/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/syncthing/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/syncthing/docs/teams","hooks_url":"https://api.github.com/repos/syncthing/docs/hooks","issue_events_url":"https://api.github.com/repos/syncthing/docs/issues/events{/number}","events_url":"https://api.github.com/repos/syncthing/docs/events","assignees_url":"https://api.github.com/repos/syncthing/docs/assignees{/user}","branches_url":"https://api.github.com/repos/syncthing/docs/branches{/branch}","tags_url":"https://api.github.com/repos/syncthing/docs/tags","blobs_url":"https://api.github.com/repos/syncthing/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/syncthing/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/syncthing/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/syncthing/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/syncthing/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/syncthing/docs/languages","stargazers_url":"https://api.github.com/repos/syncthing/docs/stargazers","contributors_url":"https://api.github.com/repos/syncthing/docs/contributors","subscribers_url":"https://api.github.com/repos/syncthing/docs/subscribers","subscription_url":"https://api.github.com/repos/syncthing/docs/subscription","commits_url":"https://api.github.com/repos/syncthing/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/syncthing/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/syncthing/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/syncthing/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/syncthing/docs/contents/{+path}","compare_url":"https://api.github.com/repos/syncthing/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/syncthing/docs/merges","archive_url":"https://api.github.com/repos/syncthing/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/syncthing/docs/downloads","issues_url":"https://api.github.com/repos/syncthing/docs/issues{/number}","pulls_url":"https://api.github.com/repos/syncthing/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/syncthing/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/syncthing/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/syncthing/docs/labels{/name}","releases_url":"https://api.github.com/repos/syncthing/docs/releases{/id}","created_at":"2015-05-26T07:38:21Z","updated_at":"2015-10-26T22:02:52Z","pushed_at":"2015-11-02T21:26:10Z","git_url":"git://github.com/syncthing/docs.git","ssh_url":"git@github.com:syncthing/docs.git","clone_url":"https://github.com/syncthing/docs.git","svn_url":"https://github.com/syncthing/docs","homepage":"http://docs.syncthing.net/","size":3336,"stargazers_count":10,"watchers_count":10,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":36,"mirror_url":null,"open_issues_count":10,"forks":36,"open_issues":10,"watchers":10,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/syncthing/docs/pulls/67"},"html":{"href":"https://github.com/syncthing/docs/pull/67"},"issue":{"href":"https://api.github.com/repos/syncthing/docs/issues/67"},"comments":{"href":"https://api.github.com/repos/syncthing/docs/issues/67/comments"},"review_comments":{"href":"https://api.github.com/repos/syncthing/docs/pulls/67/comments"},"review_comment":{"href":"https://api.github.com/repos/syncthing/docs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/syncthing/docs/pulls/67/commits"},"statuses":{"href":"https://api.github.com/repos/syncthing/docs/statuses/78f154577f6b6454040b4a6a1734924c353355a4"}}}}