{"action":"created","comment":{"url":"https://api.github.com/repos/SmingHub/Sming/pulls/comments/87759549","pull_request_review_id":8357790,"id":87759549,"diff_hunk":"@@ -0,0 +1,513 @@\n+/* \n+ * File:   WebsocketClient.cpp\n+ * Author: https://github.com/hrsavla\n+ *\n+ * Created on August 4, 2015, 1:37 PM\n+ * This Websocket Client library is ported by me into Sming from  \n+ * https://github.com/MORA99/Stokerbot/tree/master/Libraries/WebSocketClient \n+ * \n+ * \n+ */\n+\n+#include \"WebsocketClient.h\"\n+\n+WebsocketClient::WebsocketClient(bool autoDestruct /*= false*/) :\n+\t\tTcpClient(autoDestruct)\n+{\n+\tthis->Mode = ws_Disconnected;\n+\tthis->rxcallback = NULL;\n+\tthis->completecallback = NULL;\n+\tthis->connectedcallback = NULL;\n+}\n+\n+WebsocketClient::~WebsocketClient()\n+{\n+\n+}\n+\n+\n+/* Function Name: setOnReceiveCallback\n+ * Description: This function is used to set Receive callback function\n+ * Parameters: Callback function like wsMessageReceived(String message)\n+ */\n+void WebsocketClient::setOnReceiveCallback(WebSocketRxCallback _rxcallback)\n+{\n+    this->rxcallback = _rxcallback;\n+}\n+\n+/* Function Name: setOnDisconnectedCallback\n+ * Description: This function is used to set Disconnected callback function\n+ * Parameters: Callback function like  wsDisconnected(bool success)\n+ */\n+void WebsocketClient::setOnDisconnectedCallback(WebSocketCompleteCallback _completecallback)\n+{\n+\tthis->completecallback =_completecallback;\n+}\n+\n+\n+/* Function Name: setOnConnectedCallback\n+ * Description: This function is used to set Connected callback function\n+ * Parameters: Callback function like connectedCallback(wsMode  Mode)\n+ */\n+void WebsocketClient::setOnConnectedCallback(WebSocketConnectedCallback _connectedcallback)\n+{\n+\tthis->connectedcallback = _connectedcallback;\n+}\n+\n+\n+\n+/* Function Name: connect\n+ * Description: This function is called to start Websocket Client connection to Server\n+ * Parameters: url  - Url of server in String like echo.websocket.org\n+ * \t\t\t  WebsocketRxCallback  - Callback function for recieved messages like wsMessageReceived(String message)\n+ * \t\t\t  WebSocketCompleteCallback - Callback function which lets user know\n+ * \t\t\t  \t\t\t\t\t\t\twebsocket client connection is closed.\n+ * \t\t\t  \t\t\t\t\t\t\teg. wsDisconnected(bool success)\n+ *\n+ */\n+bool WebsocketClient::connect(String url)\n+{\n+\tthis->uri = URL(url);\n+\tthis->_url = url;\n+\tTcpClient::connect(uri.Host,uri.Port);\n+\tdebugf(\"Connecting to Server\");\n+\tunsigned char keyStart[17];\n+\tchar b64Key[25];\n+\tMode = ws_Connecting; // Server Connected / WS Upgrade request sent\n+\n+\trandomSeed(analogRead(0));\n+\n+\tfor (int i = 0; i < 16; ++i)\n+\t{\n+\t\tkeyStart[i] = (char) random(1, 256);\n+\t}\n+\n+\tbase64_encode(16, (const unsigned char*) keyStart, 24, (char*) b64Key);\n+\n+\tfor (int i = 0; i < 24; ++i)\n+\t{\n+\t\tkey[i] = b64Key[i];\n+\t}\n+\tString protocol = \"chat\";\n+\tsendString(\"GET \");\n+\tif (uri.Path != \"\")\n+\t{\n+\t\tsendString(uri.Path);\n+\t}\n+\telse\n+\t{\n+\t\tsendString(\"/\");\n+\t}\n+\tsendString(\" HTTP/1.1\\r\\n\");\n+\tsendString(\"Upgrade: websocket\\r\\n\");\n+\tsendString(\"Connection: Upgrade\\r\\n\");\n+\tsendString(\"Host: \");\n+\tsendString(uri.Host);\n+\tsendString(\"\\r\\n\");\n+\tsendString(\"Sec-WebSocket-Key: \");\n+\tsendString(key);\n+\tsendString(\"\\r\\n\");\n+\tsendString(\"Sec-WebSocket-Protocol: \");\n+\tsendString(protocol);\n+\tsendString(\"\\r\\n\");\n+\tsendString(\"Sec-WebSocket-Version: 13\\r\\n\");\n+\tsendString(\"\\r\\n\", false);\n+\treturn true;\n+\n+}\n+\n+/* Function Name: onConnected\n+ * Description: This function is called when Websocket Client is Connected to Server\n+ * Parameters: err - err_t state\n+ * \t\t\tif err = ERR_OK (0) then connection is successful. You can then send data.\n+ */\n+err_t WebsocketClient::onConnected(err_t err)\n+{\n+\tif (err == ERR_OK)\n+\t{\n+\t\t//Mode = ws_Connecting;\n+\t\t//\tdebugf(\"***OnConnected CALLED**** - %d\", err); // No longer needed\n+\n+\t}\n+\n+\tTcpClient::onConnected(err);\n+}\n+\n+/* Function Name: onError\n+ * Description: This function is called when Websocket Client is Connected to Server\n+ * Parameters: err - err_t state\n+ * \t\t\tStandard error codes and their meaning#define\n+ * \t\t\tERR_OK          0    No error, everything OK.\n+ * \t\t\tERR_MEM        -1    Out of memory error.\n+ *    \t\tERR_BUF        -2    Buffer error.\n+ * \t\t\tERR_TIMEOUT    -3    Timeout.\n+ *  \t\tERR_RTE        -4    Routing problem.\n+ *\t\t\tERR_INPROGRESS -5    Operation in progress\n+ *\t\t\tERR_VAL        -6    Illegal value.\n+ *\t\t\tERR_WOULDBLOCK -7    Operation would block.\n+ *\t\t\tERR_ABRT       -8    Connection aborted.       ***Common Cause\n+ *\t\t\tERR_RST        -9    Connection reset.        *** Common Cause\n+ *\t\t\tERR_CLSD       -10   Connection closed.\n+ *\t\t\tERR_CONN       -11   Not connected.\n+ *\n+ */\n+void WebsocketClient::onError(err_t err)\n+{\n+\n+\tif ((err == ERR_ABRT) || (err == ERR_RST))\n+\t{\n+\t\tdebugf(\"TCP Connection Reseted or Aborted\", err);\n+\n+\t}\n+\telse\n+\t{\n+\t\tdebugf(\"Error  %d Occured \", err);\n+\t}\n+\tTcpClient::onError(err);\n+\n+}\n+\n+/* Function Name: verifyKey\n+ * Description: It verifies Encrypted key sent by server\n+ * Parameters: buf  -  buffer received \n+ *             size - size of buffer             \n+ */\n+bool WebsocketClient::verifyKey(char* buf, int size)\n+{\n+\tString dd = String(buf);\n+\tuint8_t s = dd.indexOf(\"Sec-WebSocket-Accept: \");\n+\tuint8_t t = dd.indexOf(\"\\r\\n\", s);\n+\tString serverKey = dd.substring(s + 22, t);\n+\t//debugf(\"ServerKey : %s\",serverKey.c_str());\n+\tString hash = key + \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\n+\tunsigned char data[20];\n+\tchar secure[20 * 4];\n+\tsha1(data, hash.c_str(), hash.length());\n+\tbase64_encode(20, data, 20 * 4, secure);\n+\n+\t//debugf(\"clienKey : %s\",secure);\n+\t// if the keys match, good to go\n+\treturn serverKey.equals(String(secure)); //b64Result\n+}\n+\n+/* Function Name: onFinished\n+ * Description: This function is called when Websocket Client is Closed\n+ * Parameters: finishState - State of client             \n+ */\n+void WebsocketClient::onFinished(TcpClientState finishState)\n+{\n+\tMode = ws_Disconnected;\n+\tif (finishState == eTCS_Failed)\n+\t{\n+\t\t//  restart();\n+\t\tdebugf(\"Tcp Client failure...\");\n+\t\tthis->completecallback(false);\n+\t}\n+\telse\n+\t{\n+\t\tdebugf(\"Websocket Closed Normally.\");\n+\t\tthis->completecallback(true);\n+\t}\n+\tTcpClient::onFinished(finishState);\n+}\n+\n+\n+\n+/* Function Name: sendPing\n+ * Description: Sending Ping packet to verify Server is connected\n+ * \t\t\t\tPing can also be send to keep connection alive.\n+ * Parameters:       \n+ */\n+void WebsocketClient::sendPing()\n+{\n+\tuint8_t buf[2] =\n+\t{ 0x89, 0x00 };\n+\tdebugf(\"Sending PING\");\n+\tsend((char*) buf, 2, false);\n+}\n+\n+/* Function Name: sendPong\n+ * Description: Pong is send in response to Ping sent by Server\n+ * Parameters:       \n+ */\n+void WebsocketClient::sendPong()\n+{\n+\tuint8_t buf[2] =\n+\t{ 0x8A, 0x00 };\n+\tdebugf(\"Sending PONG\");\n+\tsend((char*) buf, 2, false);\n+}\n+\n+/* Function Name: disconnect\n+ * Description: Close Websocket Client cleanly.\n+ * Parameters:       \n+ */\n+void WebsocketClient::disconnect()\n+{\n+\tdebugf(\"Terminating Websocket connection.\");\n+\tMode = ws_Disconnected;\n+\t// Should send 0x87, 0x00 to server to tell it that I'm quitting here.\n+\tuint8_t buf[2] =\n+\t{ 0x87, 0x00 };\n+\tsend((char*) buf, 2, true);\n+\t//TcpClient::flush();\n+\t//TcpClient::close();\n+}\n+\n+\n+/* Function Name: sendMessage\n+ * Description: Send Text message to Websocket Server\n+ *              Max length of message permitted is 0xffff (65535) bytes\n+ * Parameters: msg - Message char array \n+ *             length - length of msg char array\n+ */\n+void WebsocketClient::sendMessage(char* msg, uint16_t length)\n+{\n+\t/*\n+\t +-+-+-+-+-------+-+-------------+-------------------------------+\n+\t 0                   1                   2                   3\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\n+\t +-+-+-+-+-------+-+-------------+-------------------------------+\n+\t |F|R|R|R| opcode|M| Payload len |    Extended payload length    |\n+\t |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |\n+\t |N|V|V|V|       |S|             |   (if payload len==126/127)   |\n+\t | |1|2|3|       |K|             |                               |\n+\t +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +\n+\t |     Extended payload length continued, if payload len == 127  |\n+\t + - - - - - - - - - - - - - - - +-------------------------------+\n+\t |                               | Masking-key, if MASK set to 1 |\n+\t +-------------------------------+-------------------------------+\n+\t | Masking-key (continued)       |          Payload Data         |\n+\t +-------------------------------- - - - - - - - - - - - - - - - +\n+\t :                     Payload Data continued ...                :\n+\t + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +\n+\t |                     Payload Data continued ...                |\n+\t +---------------------------------------------------------------+\n+\n+\t Opcodes\n+\t 0x00: this frame continues the payload from the last.\n+\t 0x01: this frame includes utf-8 text data.\n+\t 0x02: this frame includes binary data.\n+\t 0x08: this frame terminates the connection.\n+\t 0x09: this frame is a ping.\n+\t 0x0A: this frame is a pong.\n+\t */\n+\tuint8_t buffer[500];\n+\tuint8_t i = 0;\n+\tbuffer[i++] = 0x80 | 0x01; //FINN = 1 and Sending Text Data\n+\n+\t/*\n+\t payload_len (7 bits): the length of the payload.\n+\n+\t 0-125 mean the payload is that long.\n+\t 126 means that the following two bytes indicate the length.\n+\t 127 means the next 8 bytes indicate the length.\n+\n+\t So it comes in ~7bit, 16bit and 64bit.\n+\t */\n+\n+\tif (length <= 125)\n+\t{\n+\t\tbuffer[i++] = 0x80 | length; //Setting MASK bit and length\n+\t}\n+\telse\n+\t{\n+\t\tbuffer[i++] = 0xFE; // Mask bit + 126\n+\t\tbuffer[i++] = (uint8_t) (length >> 8);\n+\t\tbuffer[i++] = (uint8_t) (length & 0xFF);\n+\t}\n+\t//64bit outgoing messenges not supported\n+\n+\tbyte mask[4];\n+\tfor (uint8_t j = 0; j < 4; j++)\n+\t{\n+\t\tmask[j] = random(0, 255);\n+\t\tbuffer[i++] = mask[j];\n+\t}\n+\tfor (uint16_t j = 0; j < length; j++)\n+\t{\n+\t\tbuffer[i++] = (msg[j] ^ mask[j % 4]);\n+\t}\n+\tsend((char*) buffer, i, false);\n+}\n+\n+/* Function Name: sendBinary\n+ * Description: Send Binary message to Websocket Server\n+ *              Max length of message permitted is 0xffff (65535) bytes\n+ * Parameters: msg - Message int8 array \n+ *             length - length of msg  array\n+ */\n+void WebsocketClient::sendBinary(uint8_t* msg, uint16_t length)\n+{\n+\tuint8_t buffer[500];\n+\tuint8_t i = 0;\n+\tbuffer[i++] = 0x80 | 0x02; //FINN = 1 and Sending Binary Data\n+\n+\tif (length <= 125)\n+\t{\n+\t\tbuffer[i++] = 0x80 | length; //Setting MASK bit and length\n+\t}\n+\telse\n+\t{\n+\t\tbuffer[i++] = 0xFE; // Mask bit + 126\n+\t\tbuffer[i++] = (uint8_t) (length >> 8);\n+\t\tbuffer[i++] = (uint8_t) (length & 0xFF);\n+\t}\n+\t//64bit outgoing messenges not supported\n+\n+\tbyte mask[4];\n+\tfor (uint8_t j = 0; j < 4; j++)\n+\t{\n+\t\tmask[j] = random(0, 255);\n+\t\tbuffer[i++] = mask[j];\n+\t}\n+\tfor (uint16_t j = 0; j < length; j++)\n+\t{\n+\t\tbuffer[i++] = (msg[j] ^ mask[j % 4]);\n+\t}\n+\tsend((char*) buffer, i, false); // Need support from TcpClient to send binary\n+}\n+\n+/* Function Name: onReceive\n+ * Description: It process message sent byWebsocket Server\n+ *              Max length of message permitted is 0xffff (65535) bytes\n+ * Parameters: buf - pbuf array \n+ */\n+err_t WebsocketClient::onReceive(pbuf* buf)\n+{\n+\tif (buf == NULL)\n+\t{\n+\t\t// Disconnected, close it\n+\t\tTcpClient::onReceive(buf);\n+\t}\n+\telse\n+\t{\n+\t\tuint16_t size = buf->tot_len;\n+\t\tchar* data = new char[size + 1];\n+\t\tpbuf_copy_partial(buf, data, size, 0);\n+\t\tdata[size] = '\\0';\n+\n+\t\t//  debugf(\"%s\", data); //print received buffer\n+\t\tswitch (Mode)\n+\t\t{\n+\t\tcase ws_Connecting:\n+\t\t\tif (verifyKey(data, size) == true)\n+\t\t\t{\n+\t\t\t\tMode = ws_Connected;\n+\t\t\t\tthis->connectedcallback(Mode);\n+\t\t\t\t//   debugf(\"Key Verified. Websocket Handshake completed\");\n+\t\t\t\tsendPing();\n+\t\t\t}\n+\t\t\telse\n+\t\t\t{\n+\t\t\t\tMode = ws_Disconnected; // Handshake was not proper.\n+\t\t\t\tthis->connectedcallback(Mode);\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase ws_Connected:\n+\t\t\t// Parsing received Websocket packet\n+\t\t\tuint8_t op = data[0] & 0b00001111; // Extracting Opcode\n+\t\t\tuint8_t fin = data[0] & 0b10000000; // Extracting Fin Bit (Single Frame)\n+\t\t\t// debugf(\"Opcode : 0x%x\",op);\n+\t\t\t// debugf(\"Fin : 0x%x\",fin);\n+\t\t\tif (op == 0x00 || op == 0x01 || op == 0x02) //Data\n+\t\t\t{\n+\t\t\t\tif (fin > 0)\n+\t\t\t\t{\n+\t\t\t\t\t//  debugf(\"Single frame message\");\n+\t\t\t\t\tchar masked = data[1] & 0b10000000; // extracting Mask bit\n+\t\t\t\t\tuint16_t len = data[1] & 0b01111111; // length of data\n+\t\t\t\t\tuint16_t cnt = 2;\n+\t\t\t\t\tif (len == 126)\n+\t\t\t\t\t{\n+\t\t\t\t\t\t//next 2 bytes are length\n+\t\t\t\t\t\tlen = data[cnt++];\n+\t\t\t\t\t\tlen << 8;\n+\t\t\t\t\t\tlen = len | data[cnt++];\n+\t\t\t\t\t}\n+\t\t\t\t\tif (len == 127)\n+\t\t\t\t\t{\n+\t\t\t\t\t\t//next 8 bytes are length\n+\t\t\t\t\t\tdebugf(\"64bit messenges not supported\"); // Too big for Esp8266 to handle\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t}\n+\t\t\t\t\t// debugf(\"Message is %d chars long\",len);\n+\n+\t\t\t\t\t//Generally server replies are not masked, but RFC does not forbid it\n+\t\t\t\t\tuint8_t mask[4];\n+\t\t\t\t\tif (masked > 0)\n+\t\t\t\t\t{\n+\t\t\t\t\t\tmask[0] = data[cnt++];\n+\t\t\t\t\t\tmask[1] = data[cnt++];\n+\t\t\t\t\t\tmask[2] = data[cnt++];\n+\t\t\t\t\t\tmask[3] = data[cnt++];\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tuint8_t rxdata[len + 1]; //Max 16bit length message, so 65kbyte ...","path":"Sming/SmingCore/Network/WebsocketClient.cpp","position":447,"original_position":447,"commit_id":"a189e94b186c5b8f82a9ad6f71a25e4b28023ff6","original_commit_id":"a189e94b186c5b8f82a9ad6f71a25e4b28023ff6","user":{"login":"ADiea","id":6862731,"avatar_url":"https://avatars.githubusercontent.com/u/6862731?v=3","gravatar_id":"","url":"https://api.github.com/users/ADiea","html_url":"https://github.com/ADiea","followers_url":"https://api.github.com/users/ADiea/followers","following_url":"https://api.github.com/users/ADiea/following{/other_user}","gists_url":"https://api.github.com/users/ADiea/gists{/gist_id}","starred_url":"https://api.github.com/users/ADiea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ADiea/subscriptions","organizations_url":"https://api.github.com/users/ADiea/orgs","repos_url":"https://api.github.com/users/ADiea/repos","events_url":"https://api.github.com/users/ADiea/events{/privacy}","received_events_url":"https://api.github.com/users/ADiea/received_events","type":"User","site_admin":false},"body":"should be carefull here 65k on stack is huge will kill esp instantly, very suited for overflow attacks.\r\nI would allocate on heap a max size and the application must be written in such a way to never send more than x bytes","created_at":"2016-11-14T09:04:41Z","updated_at":"2016-11-14T09:04:41Z","html_url":"https://github.com/SmingHub/Sming/pull/795#discussion_r87759549","pull_request_url":"https://api.github.com/repos/SmingHub/Sming/pulls/795","_links":{"self":{"href":"https://api.github.com/repos/SmingHub/Sming/pulls/comments/87759549"},"html":{"href":"https://github.com/SmingHub/Sming/pull/795#discussion_r87759549"},"pull_request":{"href":"https://api.github.com/repos/SmingHub/Sming/pulls/795"}}},"pull_request":{"url":"https://api.github.com/repos/SmingHub/Sming/pulls/795","id":93170840,"html_url":"https://github.com/SmingHub/Sming/pull/795","diff_url":"https://github.com/SmingHub/Sming/pull/795.diff","patch_url":"https://github.com/SmingHub/Sming/pull/795.patch","issue_url":"https://api.github.com/repos/SmingHub/Sming/issues/795","number":795,"state":"open","locked":false,"title":"Feature/websocket client","user":{"login":"slaff","id":247452,"avatar_url":"https://avatars.githubusercontent.com/u/247452?v=3","gravatar_id":"","url":"https://api.github.com/users/slaff","html_url":"https://github.com/slaff","followers_url":"https://api.github.com/users/slaff/followers","following_url":"https://api.github.com/users/slaff/following{/other_user}","gists_url":"https://api.github.com/users/slaff/gists{/gist_id}","starred_url":"https://api.github.com/users/slaff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slaff/subscriptions","organizations_url":"https://api.github.com/users/slaff/orgs","repos_url":"https://api.github.com/users/slaff/repos","events_url":"https://api.github.com/users/slaff/events{/privacy}","received_events_url":"https://api.github.com/users/slaff/received_events","type":"User","site_admin":false},"body":"Rebase of #258 ","created_at":"2016-11-10T15:24:07Z","updated_at":"2016-11-14T09:04:41Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ecbc5aa797bffb831cce5541e44052f12bfb6298","assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/SmingHub/Sming/milestones/6","html_url":"https://github.com/SmingHub/Sming/milestones/2.1.5","labels_url":"https://api.github.com/repos/SmingHub/Sming/milestones/6/labels","id":2127542,"number":6,"title":"2.1.5","description":null,"creator":{"login":"slaff","id":247452,"avatar_url":"https://avatars.githubusercontent.com/u/247452?v=3","gravatar_id":"","url":"https://api.github.com/users/slaff","html_url":"https://github.com/slaff","followers_url":"https://api.github.com/users/slaff/followers","following_url":"https://api.github.com/users/slaff/following{/other_user}","gists_url":"https://api.github.com/users/slaff/gists{/gist_id}","starred_url":"https://api.github.com/users/slaff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slaff/subscriptions","organizations_url":"https://api.github.com/users/slaff/orgs","repos_url":"https://api.github.com/users/slaff/repos","events_url":"https://api.github.com/users/slaff/events{/privacy}","received_events_url":"https://api.github.com/users/slaff/received_events","type":"User","site_admin":false},"open_issues":2,"closed_issues":0,"state":"open","created_at":"2016-11-10T16:48:16Z","updated_at":"2016-11-10T16:48:27Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/SmingHub/Sming/pulls/795/commits","review_comments_url":"https://api.github.com/repos/SmingHub/Sming/pulls/795/comments","review_comment_url":"https://api.github.com/repos/SmingHub/Sming/pulls/comments{/number}","comments_url":"https://api.github.com/repos/SmingHub/Sming/issues/795/comments","statuses_url":"https://api.github.com/repos/SmingHub/Sming/statuses/a189e94b186c5b8f82a9ad6f71a25e4b28023ff6","head":{"label":"slaff:feature/websocket-client","ref":"feature/websocket-client","sha":"a189e94b186c5b8f82a9ad6f71a25e4b28023ff6","user":{"login":"slaff","id":247452,"avatar_url":"https://avatars.githubusercontent.com/u/247452?v=3","gravatar_id":"","url":"https://api.github.com/users/slaff","html_url":"https://github.com/slaff","followers_url":"https://api.github.com/users/slaff/followers","following_url":"https://api.github.com/users/slaff/following{/other_user}","gists_url":"https://api.github.com/users/slaff/gists{/gist_id}","starred_url":"https://api.github.com/users/slaff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slaff/subscriptions","organizations_url":"https://api.github.com/users/slaff/orgs","repos_url":"https://api.github.com/users/slaff/repos","events_url":"https://api.github.com/users/slaff/events{/privacy}","received_events_url":"https://api.github.com/users/slaff/received_events","type":"User","site_admin":false},"repo":{"id":44238465,"name":"Sming","full_name":"slaff/Sming","owner":{"login":"slaff","id":247452,"avatar_url":"https://avatars.githubusercontent.com/u/247452?v=3","gravatar_id":"","url":"https://api.github.com/users/slaff","html_url":"https://github.com/slaff","followers_url":"https://api.github.com/users/slaff/followers","following_url":"https://api.github.com/users/slaff/following{/other_user}","gists_url":"https://api.github.com/users/slaff/gists{/gist_id}","starred_url":"https://api.github.com/users/slaff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slaff/subscriptions","organizations_url":"https://api.github.com/users/slaff/orgs","repos_url":"https://api.github.com/users/slaff/repos","events_url":"https://api.github.com/users/slaff/events{/privacy}","received_events_url":"https://api.github.com/users/slaff/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/slaff/Sming","description":"Sming - Open Source framework for high efficiency native ESP8266 development","fork":true,"url":"https://api.github.com/repos/slaff/Sming","forks_url":"https://api.github.com/repos/slaff/Sming/forks","keys_url":"https://api.github.com/repos/slaff/Sming/keys{/key_id}","collaborators_url":"https://api.github.com/repos/slaff/Sming/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/slaff/Sming/teams","hooks_url":"https://api.github.com/repos/slaff/Sming/hooks","issue_events_url":"https://api.github.com/repos/slaff/Sming/issues/events{/number}","events_url":"https://api.github.com/repos/slaff/Sming/events","assignees_url":"https://api.github.com/repos/slaff/Sming/assignees{/user}","branches_url":"https://api.github.com/repos/slaff/Sming/branches{/branch}","tags_url":"https://api.github.com/repos/slaff/Sming/tags","blobs_url":"https://api.github.com/repos/slaff/Sming/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/slaff/Sming/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/slaff/Sming/git/refs{/sha}","trees_url":"https://api.github.com/repos/slaff/Sming/git/trees{/sha}","statuses_url":"https://api.github.com/repos/slaff/Sming/statuses/{sha}","languages_url":"https://api.github.com/repos/slaff/Sming/languages","stargazers_url":"https://api.github.com/repos/slaff/Sming/stargazers","contributors_url":"https://api.github.com/repos/slaff/Sming/contributors","subscribers_url":"https://api.github.com/repos/slaff/Sming/subscribers","subscription_url":"https://api.github.com/repos/slaff/Sming/subscription","commits_url":"https://api.github.com/repos/slaff/Sming/commits{/sha}","git_commits_url":"https://api.github.com/repos/slaff/Sming/git/commits{/sha}","comments_url":"https://api.github.com/repos/slaff/Sming/comments{/number}","issue_comment_url":"https://api.github.com/repos/slaff/Sming/issues/comments{/number}","contents_url":"https://api.github.com/repos/slaff/Sming/contents/{+path}","compare_url":"https://api.github.com/repos/slaff/Sming/compare/{base}...{head}","merges_url":"https://api.github.com/repos/slaff/Sming/merges","archive_url":"https://api.github.com/repos/slaff/Sming/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/slaff/Sming/downloads","issues_url":"https://api.github.com/repos/slaff/Sming/issues{/number}","pulls_url":"https://api.github.com/repos/slaff/Sming/pulls{/number}","milestones_url":"https://api.github.com/repos/slaff/Sming/milestones{/number}","notifications_url":"https://api.github.com/repos/slaff/Sming/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/slaff/Sming/labels{/name}","releases_url":"https://api.github.com/repos/slaff/Sming/releases{/id}","deployments_url":"https://api.github.com/repos/slaff/Sming/deployments","created_at":"2015-10-14T09:42:53Z","updated_at":"2016-11-02T14:52:47Z","pushed_at":"2016-11-14T09:04:09Z","git_url":"git://github.com/slaff/Sming.git","ssh_url":"git@github.com:slaff/Sming.git","clone_url":"https://github.com/slaff/Sming.git","svn_url":"https://github.com/slaff/Sming","homepage":null,"size":29638,"stargazers_count":2,"watchers_count":2,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":1,"forks":3,"open_issues":1,"watchers":2,"default_branch":"tasty"}},"base":{"label":"SmingHub:develop","ref":"develop","sha":"78291edde864d7cae14ab2d3f5f156b5faa09f95","user":{"login":"SmingHub","id":14863779,"avatar_url":"https://avatars.githubusercontent.com/u/14863779?v=3","gravatar_id":"","url":"https://api.github.com/users/SmingHub","html_url":"https://github.com/SmingHub","followers_url":"https://api.github.com/users/SmingHub/followers","following_url":"https://api.github.com/users/SmingHub/following{/other_user}","gists_url":"https://api.github.com/users/SmingHub/gists{/gist_id}","starred_url":"https://api.github.com/users/SmingHub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SmingHub/subscriptions","organizations_url":"https://api.github.com/users/SmingHub/orgs","repos_url":"https://api.github.com/users/SmingHub/repos","events_url":"https://api.github.com/users/SmingHub/events{/privacy}","received_events_url":"https://api.github.com/users/SmingHub/received_events","type":"Organization","site_admin":false},"repo":{"id":32271212,"name":"Sming","full_name":"SmingHub/Sming","owner":{"login":"SmingHub","id":14863779,"avatar_url":"https://avatars.githubusercontent.com/u/14863779?v=3","gravatar_id":"","url":"https://api.github.com/users/SmingHub","html_url":"https://github.com/SmingHub","followers_url":"https://api.github.com/users/SmingHub/followers","following_url":"https://api.github.com/users/SmingHub/following{/other_user}","gists_url":"https://api.github.com/users/SmingHub/gists{/gist_id}","starred_url":"https://api.github.com/users/SmingHub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SmingHub/subscriptions","organizations_url":"https://api.github.com/users/SmingHub/orgs","repos_url":"https://api.github.com/users/SmingHub/repos","events_url":"https://api.github.com/users/SmingHub/events{/privacy}","received_events_url":"https://api.github.com/users/SmingHub/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/SmingHub/Sming","description":"Sming - Open Source framework for high efficiency native ESP8266 development","fork":false,"url":"https://api.github.com/repos/SmingHub/Sming","forks_url":"https://api.github.com/repos/SmingHub/Sming/forks","keys_url":"https://api.github.com/repos/SmingHub/Sming/keys{/key_id}","collaborators_url":"https://api.github.com/repos/SmingHub/Sming/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/SmingHub/Sming/teams","hooks_url":"https://api.github.com/repos/SmingHub/Sming/hooks","issue_events_url":"https://api.github.com/repos/SmingHub/Sming/issues/events{/number}","events_url":"https://api.github.com/repos/SmingHub/Sming/events","assignees_url":"https://api.github.com/repos/SmingHub/Sming/assignees{/user}","branches_url":"https://api.github.com/repos/SmingHub/Sming/branches{/branch}","tags_url":"https://api.github.com/repos/SmingHub/Sming/tags","blobs_url":"https://api.github.com/repos/SmingHub/Sming/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/SmingHub/Sming/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/SmingHub/Sming/git/refs{/sha}","trees_url":"https://api.github.com/repos/SmingHub/Sming/git/trees{/sha}","statuses_url":"https://api.github.com/repos/SmingHub/Sming/statuses/{sha}","languages_url":"https://api.github.com/repos/SmingHub/Sming/languages","stargazers_url":"https://api.github.com/repos/SmingHub/Sming/stargazers","contributors_url":"https://api.github.com/repos/SmingHub/Sming/contributors","subscribers_url":"https://api.github.com/repos/SmingHub/Sming/subscribers","subscription_url":"https://api.github.com/repos/SmingHub/Sming/subscription","commits_url":"https://api.github.com/repos/SmingHub/Sming/commits{/sha}","git_commits_url":"https://api.github.com/repos/SmingHub/Sming/git/commits{/sha}","comments_url":"https://api.github.com/repos/SmingHub/Sming/comments{/number}","issue_comment_url":"https://api.github.com/repos/SmingHub/Sming/issues/comments{/number}","contents_url":"https://api.github.com/repos/SmingHub/Sming/contents/{+path}","compare_url":"https://api.github.com/repos/SmingHub/Sming/compare/{base}...{head}","merges_url":"https://api.github.com/repos/SmingHub/Sming/merges","archive_url":"https://api.github.com/repos/SmingHub/Sming/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/SmingHub/Sming/downloads","issues_url":"https://api.github.com/repos/SmingHub/Sming/issues{/number}","pulls_url":"https://api.github.com/repos/SmingHub/Sming/pulls{/number}","milestones_url":"https://api.github.com/repos/SmingHub/Sming/milestones{/number}","notifications_url":"https://api.github.com/repos/SmingHub/Sming/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/SmingHub/Sming/labels{/name}","releases_url":"https://api.github.com/repos/SmingHub/Sming/releases{/id}","deployments_url":"https://api.github.com/repos/SmingHub/Sming/deployments","created_at":"2015-03-15T16:36:22Z","updated_at":"2016-11-06T19:08:46Z","pushed_at":"2016-11-14T09:04:10Z","git_url":"git://github.com/SmingHub/Sming.git","ssh_url":"git@github.com:SmingHub/Sming.git","clone_url":"https://github.com/SmingHub/Sming.git","svn_url":"https://github.com/SmingHub/Sming","homepage":null,"size":43014,"stargazers_count":587,"watchers_count":587,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":202,"mirror_url":null,"open_issues_count":54,"forks":202,"open_issues":54,"watchers":587,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/SmingHub/Sming/pulls/795"},"html":{"href":"https://github.com/SmingHub/Sming/pull/795"},"issue":{"href":"https://api.github.com/repos/SmingHub/Sming/issues/795"},"comments":{"href":"https://api.github.com/repos/SmingHub/Sming/issues/795/comments"},"review_comments":{"href":"https://api.github.com/repos/SmingHub/Sming/pulls/795/comments"},"review_comment":{"href":"https://api.github.com/repos/SmingHub/Sming/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/SmingHub/Sming/pulls/795/commits"},"statuses":{"href":"https://api.github.com/repos/SmingHub/Sming/statuses/a189e94b186c5b8f82a9ad6f71a25e4b28023ff6"}}}}
{"actor":{"display_login":"ADiea"}}