Sfoglia il codice sorgente

Handle tcp fragmentation and also fix XSS problem. (#3275)

Philip Gladstone 3 anni fa
parent
commit
fee81bf9ad

+ 178 - 27
app/modules/enduser_setup.c

@@ -90,14 +90,14 @@ static const char dns_body[]   = { 0x00, 0x01, 0x00, 0x01,
 
 static const char http_html_gz_filename[] = "enduser_setup.html.gz";
 static const char http_html_filename[] = "enduser_setup.html";
-static const char http_header_200[] = "HTTP/1.1 200 OK\r\nCache-control:no-cache\r\nConnection:close\r\nContent-Type:text/html\r\n"; /* Note single \r\n here! */
+static const char http_header_200[] = "HTTP/1.1 200 OK\r\nCache-control:no-cache\r\nConnection:close\r\nContent-Type:text/html; charset=utf-8\r\n"; /* Note single \r\n here! */
 static const char http_header_204[] = "HTTP/1.1 204 No Content\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
 static const char http_header_302[] = "HTTP/1.1 302 Moved\r\nLocation: /\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
 static const char http_header_302_trying[] = "HTTP/1.1 302 Moved\r\nLocation: /?trying=true\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
 static const char http_header_400[] = "HTTP/1.1 400 Bad request\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
-static const char http_header_404[] = "HTTP/1.1 404 Not found\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
+static const char http_header_404[] = "HTTP/1.1 404 Not found\r\nContent-Length:10\r\nConnection:close\r\n\r\nNot found\n";
 static const char http_header_405[] = "HTTP/1.1 405 Method Not Allowed\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
-static const char http_header_500[] = "HTTP/1.1 500 Internal Error\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
+static const char http_header_500[] = "HTTP/1.1 500 Internal Error\r\nContent-Length:6\r\nConnection:close\r\n\r\nError\n";
 
 static const char http_header_content_len_fmt[] = "Content-length:%5d\r\n\r\n";
 static const char http_html_gzip_contentencoding[] = "Content-Encoding: gzip\r\n";
@@ -105,12 +105,30 @@ static const char http_html_gzip_contentencoding[] = "Content-Encoding: gzip\r\n
 /* Externally defined: static const char enduser_setup_html_default[] = ... */
 #include "enduser_setup/enduser_setup.html.gz.def.h"
 
+// The tcp_arg can be either a pointer to the scan_listener_t or http_request_buffer_t.
+// The enum defines which one it is.
+typedef enum {
+  SCAN_LISTENER_STRUCT_TYPE = 1,
+  HTTP_REQUEST_BUFFER_STRUCT_TYPE = 2
+} struct_type_t;
+
+typedef struct {
+  struct_type_t struct_type;
+} tcp_arg_t;
+
 typedef struct scan_listener
 {
+  struct_type_t struct_type;
   struct tcp_pcb *conn;
   struct scan_listener *next;
 } scan_listener_t;
 
+typedef struct {
+  struct_type_t struct_type;
+  size_t length;
+  char data[0];
+} http_request_buffer_t;
+
 typedef struct
 {
   struct espconn *espconn_dns_udp;
@@ -398,8 +416,8 @@ static err_t close_once_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
 
 /**
  * Get length of param value
- * 
- * This is being called with a fragment of the parameters passed in the 
+ *
+ * This is being called with a fragment of the parameters passed in the
  * URL for GET requests or part of the body of a POST request.
  * The string will look like one of these
  * "SecretPassword HTTP/1.1"
@@ -1124,14 +1142,13 @@ static void enduser_setup_handle_POST(struct tcp_pcb *http_client, char* data, s
     if (strncmp(data + 5, "/setwifi ", 9) == 0) // User clicked the submit button
     {
       char* body=strstr(data, "\r\n\r\n");
-      char *content_length_str = strstr(data, "Content-Length: ");
-      if( body == NULL || content_length_str == NULL)
+      if( body == NULL)
       {
         enduser_setup_http_serve_header(http_client, http_header_400, LITLEN(http_header_400));
         return;
       }
-      int bodylength = atoi(content_length_str + 16);
       body += 4; // length of the double CRLF found above
+      int bodylength = (data + data_len) - body;
       switch (enduser_setup_http_handle_credentials(body, bodylength))
       {
         case 0: {
@@ -1148,6 +1165,8 @@ static void enduser_setup_handle_POST(struct tcp_pcb *http_client, char* data, s
           ENDUSER_SETUP_ERROR_VOID("http_recvcb failed. Failed to handle wifi credentials.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
           break;
       }
+    } else {
+      enduser_setup_http_serve_header(http_client, http_header_404, LITLEN(http_header_404));
     }
 }
 
@@ -1333,27 +1352,154 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
     return ERR_ABRT;
   }
 
+  tcp_arg_t *tcp_arg_ptr = arg;
+
   if (!p) /* remote side closed, close our end too */
   {
     ENDUSER_SETUP_DEBUG("connection closed");
-    scan_listener_t *l = arg; /* if it's waiting for scan, we have a ptr here */
-    if (l)
-      remove_scan_listener (l);
+    if (tcp_arg_ptr) {
+      if (tcp_arg_ptr->struct_type == SCAN_LISTENER_STRUCT_TYPE) {
+        remove_scan_listener ((scan_listener_t *)tcp_arg_ptr);
+      } else if (tcp_arg_ptr->struct_type == HTTP_REQUEST_BUFFER_STRUCT_TYPE) {
+        free(tcp_arg_ptr);
+      }
+    }
 
     deferred_close (http_client);
     return ERR_OK;
   }
 
-  char *data = calloc (1, p->tot_len + 1);
-  if (!data)
-    return ERR_MEM;
+  http_request_buffer_t *hrb;
+  if (!tcp_arg_ptr) {
+    hrb = calloc(1, sizeof(*hrb));
+    if (!hrb) {
+      goto general_fail;
+    }
+    hrb->struct_type = HTTP_REQUEST_BUFFER_STRUCT_TYPE;
+    tcp_arg(http_client, hrb);
+  } else if (tcp_arg_ptr->struct_type == HTTP_REQUEST_BUFFER_STRUCT_TYPE) {
+    hrb = (http_request_buffer_t *) tcp_arg_ptr;
+  } else {
+    goto general_fail;
+  }
+
+  // Append the new data
+  size_t newlen = hrb->length + p->tot_len;
+  void *old_hrb = hrb;
+  hrb = realloc(hrb, sizeof(*hrb) + newlen + 1);
+  tcp_arg(http_client, hrb);
+  if (!hrb) {
+    free(old_hrb);
+    goto general_fail;
+  }
+
+  pbuf_copy_partial(p, hrb->data + hrb->length, p->tot_len, 0);
+  hrb->data[newlen] = 0;
+  hrb->length = newlen;
 
-  unsigned data_len = pbuf_copy_partial (p, data, p->tot_len, 0);
   tcp_recved (http_client, p->tot_len);
   pbuf_free (p);
 
+  // see if we have the whole request.
+  // Rely on the fact that the header should not contain a null character
+  char *end_of_header = strstr(hrb->data, "\r\n\r\n");
+  if (end_of_header == 0) {
+    return ERR_OK;
+  }
+
+  end_of_header += 4;
+
+  // We have the entire header, now see if there is any content. If we don't find the
+  // content-length header, then there is no content and we can process immediately.
+  // The content-length header can also be missing if the browser is using chunked
+  // encoding.
+
+  bool is_chunked = FALSE;
+  for (const char *hdr = hrb->data; hdr && hdr < end_of_header; hdr = strchr(hdr, '\n')) {
+    hdr += 1; // Skip the \n
+    if (strncasecmp(hdr, "transfer-encoding:", 18) == 0) {
+      const char *field = hdr + 18;
+
+      while (*field != '\n') {
+        if (memcmp(field, "chunked", 7) == 0) {
+          is_chunked = TRUE;
+          break;
+        }
+        field++;
+      }
+    }
+    if (strncasecmp(hdr, "Content-length:", 15) == 0) {
+      // There is a content-length header
+      const char *field = hdr + 15;
+      size_t extra = strtol(field + 1, 0, 10);
+      if (extra + (end_of_header - hrb->data) > hrb->length) {
+        return ERR_OK;
+      }
+    }
+  }
+
+  if (is_chunked) {
+    // More complex to determine if the whole body has arrived
+    // Format is one or more chunks each preceded by their length (in hex)
+    // A zero length chunk ends the body
+    const char *ptr = end_of_header;
+    bool seen_end = FALSE;
+
+    while (ptr < hrb->data + hrb->length && ptr > hrb->data) {
+      size_t chunk_len = strtol(ptr, 0, 16);
+      // Skip to end of chunk length (note that there can be parameters after the length)
+      ptr = strchr(ptr, '\n');
+      if (!ptr) {
+        // Don't have the entire chunk header
+        return ERR_OK;
+      }
+      ptr++;
+      ptr += chunk_len;
+      if (chunk_len == 0) {
+        seen_end = TRUE;
+        break;
+      }
+      if (ptr + 2 > hrb->data + hrb->length) {
+        // We don't have the CRLF yet
+        return ERR_OK;
+      }
+      if (memcmp(ptr, "\r\n", 2)) {
+        // Bail out here -- something bad happened
+        goto general_fail;
+      }
+      ptr += 2;
+    }
+    if (!seen_end) {
+      // Still waiting for the end chunk
+      return ERR_OK;
+    }
+
+    // Now rewrite the buffer to eliminate all the chunk headers
+    const char *src = end_of_header;
+    char *dst = end_of_header;
+
+    while (src < hrb->data + hrb->length && src > hrb->data) {
+      size_t chunk_len = strtol(src, 0, 16);
+      src = strchr(src, '\n');
+      src++;
+      if (chunk_len == 0) {
+        break;
+      }
+      memmove(dst, src, chunk_len);
+      dst += chunk_len;
+      src += chunk_len + 2;
+    }
+    *dst = '\0';    // Move the null termination down
+    hrb->length = dst - hrb->data;  // Adjust the length down
+  }
+
   err_t ret = ERR_OK;
 
+  char *data = hrb->data;
+  size_t data_len = hrb->length;
+
+  tcp_arg(http_client, 0);    // Forget the data pointer.
+
 #if ENDUSER_SETUP_DEBUG_SHOW_HTTP_REQUEST
   ENDUSER_SETUP_DEBUG(data);
 #endif
@@ -1364,7 +1510,7 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
     {
       if (enduser_setup_http_serve_html(http_client) != 0)
       {
-        ENDUSER_SETUP_ERROR("http_recvcb failed. Unable to send HTML.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
+        goto general_fail;
       }
       else
       {
@@ -1376,27 +1522,29 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
       /* Don't do an AP Scan while station is trying to connect to Wi-Fi */
       if (state->connecting == 0)
       {
-        scan_listener_t *l = malloc (sizeof (scan_listener_t));
-        if (!l)
+        scan_listener_t *sl = malloc (sizeof (scan_listener_t));
+        if (!sl)
         {
           ENDUSER_SETUP_ERROR("out of memory", ENDUSER_SETUP_ERR_OUT_OF_MEMORY, ENDUSER_SETUP_ERR_NONFATAL);
         }
 
+        sl->struct_type = SCAN_LISTENER_STRUCT_TYPE;
+
         bool already = (state->scan_listeners != NULL);
 
-        tcp_arg (http_client, l);
+        tcp_arg (http_client, sl);
         /* TODO: check if also need a tcp_err() cb, or if recv() is enough */
-        l->conn = http_client;
-        l->next = state->scan_listeners;
-        state->scan_listeners = l;
+        sl->conn = http_client;
+        sl->next = state->scan_listeners;
+        state->scan_listeners = sl;
 
         if (!already)
         {
           if (!wifi_station_scan(NULL, on_scan_done))
           {
             enduser_setup_http_serve_header(http_client, http_header_500, LITLEN(http_header_500));
-            deferred_close (l->conn);
-            l->conn = 0;
+            deferred_close (sl->conn);
+            sl->conn = 0;
             free_scan_listeners();
           }
         }
@@ -1410,13 +1558,12 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
     }
     else if (strncmp(data + 4, "/status.json", 12) == 0)
     {
-    enduser_setup_serve_status_as_json(http_client);
+      enduser_setup_serve_status_as_json(http_client);
     }
     else if (strncmp(data + 4, "/status", 7) == 0)
     {
       enduser_setup_serve_status(http_client);
     }
-
     else if (strncmp(data + 4, "/update?", 8) == 0)
     {
       switch (enduser_setup_http_handle_credentials(data, data_len))
@@ -1459,8 +1606,11 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
   deferred_close (http_client);
 
 free_out:
-  free (data);
+  free (hrb);
   return ret;
+
+general_fail:
+  ENDUSER_SETUP_ERROR("http_recvcb failed. Unable to send HTML.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
 }
 
 
@@ -1476,6 +1626,7 @@ static err_t enduser_setup_http_connectcb(void *arg, struct tcp_pcb *pcb, err_t
   }
 
   tcp_accepted (state->http_pcb);
+  tcp_arg(pcb, 0);              // Initialize to known value
   tcp_recv (pcb, enduser_setup_http_recvcb);
   tcp_nagle_disable (pcb);
   return ERR_OK;

+ 6 - 1
app/modules/enduser_setup/enduser_setup.html

@@ -274,8 +274,13 @@
 					return b.rssi - a.rssi;
 				});
 				var ops = '<option>Select a Network...</option>';
+                                var seen = {};
 				for (var i = 0; i < list.length; ++i) {
-					ops += '<option>' + list[i].ssid + '</option>';
+                                        var ssid = list[i].ssid;
+                                        if (!seen[ssid]) {
+                                            seen[ssid] = 1;
+					    ops += '<option>' + ssid.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;") + '</option>';
+                                        }
 				}
 				ap.innerHTML = ops;
 				ab.disabled = false;

+ 222 - 217
app/modules/enduser_setup/enduser_setup.html.gz.def.h

@@ -1,219 +1,224 @@
 static const char enduser_setup_html_default[] = {
-  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x95, 0x59,
-  0x7d, 0x73, 0xdc, 0xb6, 0xd1, 0xff, 0x5b, 0xcf, 0xcc, 0xf3, 0x1d, 0x56,
-  0x92, 0x6b, 0x52, 0xf6, 0x1d, 0x4f, 0xa7, 0x17, 0xc7, 0x23, 0xdd, 0x29,
-  0xe3, 0x26, 0xce, 0x4b, 0x27, 0x76, 0x3c, 0x91, 0x33, 0x69, 0xc6, 0x75,
-  0x33, 0x38, 0x12, 0x14, 0x11, 0xf3, 0x08, 0x16, 0x00, 0x25, 0x5d, 0x13,
-  0x7f, 0xf7, 0xee, 0x12, 0x8b, 0xe3, 0xd1, 0x64, 0xd4, 0x74, 0x12, 0x89,
-  0x04, 0xb0, 0xef, 0xfb, 0xc3, 0xee, 0x52, 0x5e, 0xec, 0x7f, 0xf9, 0xfd,
-  0x17, 0x6f, 0x7f, 0x7e, 0xf3, 0x12, 0x0a, 0xb7, 0x2e, 0xaf, 0xfe, 0xff,
-  0xff, 0x16, 0xfc, 0xa4, 0x37, 0x29, 0x32, 0x7c, 0xdb, 0x5b, 0xac, 0xa5,
-  0x13, 0x50, 0x89, 0xb5, 0x5c, 0x46, 0xb7, 0x4a, 0xde, 0xd5, 0xda, 0xb8,
-  0x08, 0x52, 0x5d, 0x39, 0x59, 0xb9, 0x65, 0x74, 0xa7, 0x32, 0x57, 0x2c,
-  0x33, 0x79, 0xab, 0x52, 0x39, 0x6d, 0x17, 0x13, 0x50, 0x95, 0x72, 0x4a,
-  0x94, 0x53, 0x9b, 0x8a, 0x52, 0x2e, 0xe7, 0xc9, 0x71, 0xd4, 0x0a, 0x72,
-  0xca, 0x95, 0xf2, 0xea, 0x27, 0xf5, 0x95, 0x82, 0xef, 0xf4, 0x8d, 0xaa,
-  0x16, 0x33, 0xbf, 0x43, 0x67, 0xd6, 0x6d, 0x4a, 0x09, 0x6e, 0x53, 0xcb,
-  0xa5, 0x93, 0xf7, 0x6e, 0x96, 0x5a, 0x4b, 0xfb, 0x7b, 0x4f, 0xe0, 0x37,
-  0x7a, 0xec, 0xad, 0x85, 0x41, 0x8e, 0x0b, 0x38, 0xbe, 0x6c, 0x97, 0xb5,
-  0xc8, 0x32, 0x55, 0xdd, 0x84, 0xf5, 0x47, 0xfa, 0x45, 0x3f, 0x64, 0xfe,
-  0x84, 0x5e, 0x56, 0x3a, 0xdb, 0x30, 0x6b, 0x21, 0xd5, 0x4d, 0xe1, 0x2e,
-  0x60, 0x7e, 0x7c, 0xfc, 0x17, 0xcf, 0x9d, 0xa3, 0xf1, 0xd3, 0x5c, 0xac,
-  0x55, 0xb9, 0xb9, 0x00, 0x2b, 0x2a, 0x3b, 0xb5, 0xd2, 0xa8, 0xdc, 0x1f,
-  0x92, 0xfa, 0xa9, 0x28, 0xd5, 0x0d, 0x6a, 0x4b, 0x25, 0x7a, 0x69, 0xfc,
-  0xfe, 0x4a, 0xa4, 0x1f, 0x6e, 0x8c, 0x6e, 0xaa, 0xec, 0x02, 0x0e, 0xcf,
-  0xce, 0xce, 0xb2, 0xb3, 0xb3, 0xbe, 0xee, 0x43, 0x8e, 0x09, 0xab, 0xad,
-  0xb5, 0xc5, 0x28, 0x68, 0x94, 0x22, 0x56, 0x56, 0x97, 0x8d, 0x93, 0x2c,
-  0x5f, 0xd7, 0x5b, 0x37, 0x8c, 0xb7, 0x8c, 0x57, 0x2b, 0xed, 0x9c, 0x5e,
-  0x6f, 0x97, 0xa5, 0xcc, 0xbb, 0xb3, 0x36, 0xb2, 0x17, 0x70, 0x7a, 0x72,
-  0x5c, 0xdf, 0x5f, 0xf6, 0xdc, 0x3a, 0x7b, 0xce, 0x5b, 0x5d, 0x90, 0x44,
-  0xe3, 0x74, 0xdf, 0x36, 0x55, 0xd5, 0x8d, 0xf3, 0x81, 0x69, 0x50, 0x49,
-  0xd5, 0xbe, 0x5a, 0x59, 0xca, 0x34, 0x98, 0x3b, 0xbd, 0x93, 0xab, 0x0f,
-  0x0a, 0x3d, 0xaf, 0x6b, 0x29, 0x8c, 0xa8, 0x52, 0x79, 0x01, 0x95, 0xae,
-  0x64, 0x30, 0xcd, 0x64, 0xd2, 0x4c, 0x8d, 0xc8, 0x54, 0x63, 0x07, 0x51,
-  0xcf, 0x95, 0x2c, 0x33, 0x2b, 0x59, 0x14, 0x13, 0xef, 0xb8, 0x75, 0x3f,
-  0xb5, 0x85, 0xc8, 0xf4, 0x1d, 0x6e, 0xe1, 0x7f, 0xf3, 0xf3, 0xfa, 0x1e,
-  0xe6, 0xf8, 0x63, 0x6e, 0x56, 0x22, 0x3e, 0x9e, 0x80, 0xff, 0x3f, 0x39,
-  0x3b, 0xda, 0xa1, 0x57, 0xff, 0x6e, 0xd3, 0xcb, 0x7a, 0x71, 0xeb, 0x93,
-  0xbc, 0x53, 0x1c, 0xe0, 0x14, 0x7f, 0x8d, 0x24, 0x27, 0xcf, 0x73, 0x8e,
-  0x87, 0xaa, 0xa6, 0x1c, 0x26, 0x8c, 0xdc, 0x20, 0x4c, 0x53, 0x34, 0x62,
-  0x24, 0x4c, 0x7d, 0x2f, 0x5a, 0x4b, 0x31, 0x7f, 0x2a, 0x83, 0xc3, 0x34,
-  0x4d, 0x77, 0x25, 0x4c, 0x43, 0xc2, 0xe6, 0x2c, 0x9a, 0xd3, 0xd4, 0x41,
-  0xed, 0x61, 0x67, 0x52, 0x5d, 0x6a, 0x83, 0xf6, 0x9e, 0x9c, 0x9c, 0x74,
-  0xb8, 0x44, 0xe6, 0x67, 0xa8, 0x71, 0xad, 0x2b, 0x6d, 0x6b, 0x91, 0xca,
-  0xbe, 0xdf, 0x14, 0xbc, 0xbe, 0xcd, 0xfd, 0x2c, 0x8e, 0x4b, 0xe8, 0x47,
-  0x68, 0xca, 0x7a, 0x1d, 0x66, 0x19, 0x09, 0x8c, 0xac, 0xdc, 0x83, 0x4a,
-  0x3a, 0xd4, 0xb0, 0x12, 0xe6, 0xf7, 0x71, 0x1e, 0x24, 0x7c, 0x00, 0x96,
-  0xd3, 0x3a, 0xf8, 0xdb, 0x18, 0x4b, 0x8c, 0xb5, 0x56, 0xdd, 0xb5, 0xca,
-  0x94, 0xad, 0x4b, 0xb1, 0xc1, 0xe8, 0x94, 0x3a, 0xfd, 0x30, 0x88, 0xc3,
-  0xe8, 0xed, 0xcc, 0x64, 0xaa, 0x8d, 0xf0, 0x97, 0x8b, 0x31, 0xda, 0x33,
-  0x9f, 0xb0, 0x71, 0x3e, 0x0a, 0x8d, 0xd3, 0xf9, 0xea, 0xec, 0xfc, 0xb3,
-  0x91, 0x5c, 0x0d, 0x9d, 0xbd, 0xc8, 0x75, 0xda, 0xd8, 0xc9, 0xce, 0x46,
-  0xa1, 0x6f, 0xa5, 0x81, 0xdf, 0x46, 0x41, 0x7d, 0x0c, 0x27, 0xa8, 0x94,
-  0x42, 0x32, 0xe1, 0x35, 0xba, 0xdd, 0xd3, 0xd7, 0xd5, 0xa8, 0xd3, 0x9d,
-  0x64, 0x11, 0x38, 0xa4, 0xf7, 0xb5, 0x0f, 0x8a, 0x67, 0xcf, 0x9e, 0x8d,
-  0x62, 0xcd, 0xc3, 0xb8, 0x27, 0xef, 0xac, 0x97, 0x17, 0x86, 0xe9, 0x20,
-  0x22, 0x7d, 0xa6, 0xa4, 0x71, 0xaa, 0x54, 0x6e, 0x13, 0x4c, 0x29, 0xb5,
-  0xc0, 0x90, 0xb7, 0xf5, 0x88, 0xed, 0x28, 0xa5, 0x40, 0x61, 0xa8, 0xb6,
-  0x08, 0x76, 0xdc, 0x4f, 0x39, 0x64, 0x9f, 0x9d, 0xfb, 0x88, 0xf5, 0x3c,
-  0x40, 0x7f, 0xc7, 0x61, 0xcd, 0x1e, 0x78, 0x2b, 0x06, 0x05, 0xbc, 0x2d,
-  0x06, 0xe3, 0xf7, 0x98, 0xfd, 0x18, 0x1a, 0xcd, 0xa9, 0xe9, 0x6d, 0xfd,
-  0xef, 0xc9, 0x19, 0xca, 0x3f, 0xcc, 0x8c, 0xae, 0x91, 0xab, 0x9a, 0xb4,
-  0xab, 0xfc, 0x84, 0x9f, 0xa7, 0xfe, 0xb9, 0xfa, 0x70, 0xc2, 0x0a, 0x18,
-  0xb4, 0x8c, 0xbe, 0x71, 0x19, 0x83, 0x36, 0x60, 0x64, 0x29, 0x9c, 0xba,
-  0x95, 0x7f, 0x50, 0x29, 0xc8, 0x7e, 0x4c, 0xc3, 0x1d, 0x97, 0xef, 0x5e,
-  0x8d, 0x3f, 0xe7, 0x4a, 0x35, 0x5e, 0x79, 0xfa, 0xfa, 0x45, 0x5d, 0x2a,
-  0xfb, 0x70, 0x13, 0x1a, 0x6a, 0x1f, 0x36, 0x49, 0xee, 0x53, 0x83, 0x56,
-  0x34, 0x68, 0x53, 0xe3, 0x75, 0x72, 0xd8, 0x68, 0x07, 0x25, 0x6d, 0x78,
-  0x5d, 0xfb, 0x7e, 0x18, 0xa3, 0xef, 0x3e, 0x41, 0xf6, 0xf3, 0xe7, 0xcf,
-  0x2f, 0x1f, 0xf4, 0x8b, 0x1b, 0xea, 0x73, 0x96, 0xe6, 0x9d, 0x98, 0x0f,
-  0x85, 0x2b, 0x16, 0x3c, 0xd6, 0xec, 0x99, 0x70, 0x31, 0x6b, 0x67, 0x12,
-  0x1a, 0x8a, 0x66, 0x3c, 0x0b, 0xe1, 0x2b, 0xcd, 0x15, 0x57, 0x74, 0x9a,
-  0xa9, 0x5b, 0x50, 0xd9, 0x92, 0x7b, 0x3e, 0x6d, 0xed, 0x2d, 0xb8, 0x0f,
-  0xfa, 0x55, 0x20, 0xe1, 0xd9, 0xe8, 0xdb, 0xec, 0x6a, 0x31, 0xc3, 0x9d,
-  0xfe, 0x59, 0x3e, 0xa7, 0x35, 0x6d, 0x14, 0xa7, 0x57, 0x5f, 0xe8, 0xaa,
-  0xa2, 0x52, 0xee, 0x19, 0xc0, 0x69, 0xd8, 0xe8, 0xc6, 0xc0, 0x4f, 0x6a,
-  0xfa, 0x95, 0x42, 0x1b, 0x4e, 0x03, 0x69, 0xae, 0xcd, 0x1a, 0x44, 0x4a,
-  0xfe, 0x2f, 0x0f, 0x66, 0xa8, 0xef, 0x4e, 0xe5, 0xea, 0x00, 0xd6, 0xd2,
-  0x15, 0x3a, 0x5b, 0x1e, 0xbc, 0xf9, 0xfe, 0xfa, 0xed, 0x81, 0xa7, 0x45,
-  0x62, 0xae, 0xdc, 0xa8, 0xab, 0x42, 0x42, 0x6d, 0x3e, 0x58, 0x3f, 0x65,
-  0xf1, 0x7e, 0x5a, 0x0a, 0x6b, 0x97, 0x7c, 0x89, 0xd0, 0x42, 0xbf, 0xcd,
-  0xdc, 0x9d, 0x0b, 0x8c, 0x69, 0xde, 0xc7, 0x03, 0x4c, 0x64, 0x2b, 0xb4,
-  0xcd, 0xd2, 0xd5, 0xe3, 0xc3, 0xfb, 0x93, 0xf3, 0x55, 0x7a, 0xb9, 0x98,
-  0xd1, 0x7e, 0x47, 0xc5, 0xbd, 0x09, 0xe9, 0x18, 0x95, 0x34, 0x46, 0xf2,
-  0x3b, 0x2a, 0xf3, 0xc7, 0x81, 0x9c, 0xc3, 0xc3, 0x0b, 0xdf, 0x8a, 0x91,
-  0xd3, 0x5a, 0x95, 0x79, 0x3e, 0x72, 0xf3, 0x17, 0x5a, 0x76, 0x73, 0x62,
-  0x7b, 0x57, 0x52, 0x6d, 0x0c, 0xca, 0x59, 0xea, 0x3c, 0xf7, 0x6b, 0x51,
-  0x2b, 0x27, 0x4a, 0x2c, 0x4b, 0x4b, 0xba, 0x9f, 0x50, 0x97, 0x08, 0xba,
-  0x42, 0x97, 0x08, 0xd3, 0x65, 0xd4, 0x46, 0x13, 0x5e, 0xa3, 0xbc, 0x08,
-  0x66, 0x7d, 0x6d, 0x3b, 0x5a, 0x6a, 0x8c, 0x0a, 0x06, 0x8b, 0x35, 0x85,
-  0xd5, 0x9f, 0xd1, 0xc6, 0x34, 0xeb, 0xba, 0x94, 0x4e, 0x12, 0x51, 0x4f,
-  0xfd, 0x9b, 0x20, 0xa9, 0x53, 0xbd, 0x3f, 0x9d, 0xc2, 0xcf, 0xba, 0x81,
-  0x14, 0x03, 0x2a, 0xb2, 0x0c, 0x5a, 0x53, 0x2c, 0x14, 0xd2, 0xa0, 0xac,
-  0x2a, 0x83, 0x42, 0xdc, 0x4a, 0x70, 0x85, 0x5c, 0x43, 0xad, 0x6b, 0x68,
-  0x6a, 0x24, 0xf0, 0xb8, 0x28, 0x1b, 0x01, 0xa9, 0xce, 0xe8, 0xd0, 0xe8,
-  0xe6, 0xa6, 0x20, 0x22, 0xc8, 0x55, 0x29, 0x41, 0x36, 0x16, 0x3d, 0x30,
-  0x62, 0x6d, 0x13, 0x22, 0x9a, 0x4e, 0xfb, 0x7e, 0x7a, 0xa7, 0x0e, 0x6c,
-  0xb3, 0x5a, 0x2b, 0x77, 0x00, 0xb7, 0xa2, 0x6c, 0x70, 0x79, 0x8d, 0x7a,
-  0x0e, 0x82, 0x59, 0x8b, 0x19, 0x81, 0xcc, 0x2f, 0xc6, 0x60, 0x7b, 0xb2,
-  0x85, 0xed, 0xfc, 0xea, 0xba, 0x49, 0x53, 0x69, 0xed, 0x3e, 0x42, 0x34,
-  0xa0, 0x39, 0xd0, 0x29, 0x5a, 0x07, 0x78, 0xa3, 0x93, 0x26, 0x60, 0xbb,
-  0x10, 0x16, 0xac, 0xe7, 0xcb, 0x9b, 0xb2, 0xdc, 0x40, 0xea, 0xb1, 0x2f,
-  0x31, 0xe2, 0xba, 0x75, 0xc4, 0xe7, 0x89, 0x31, 0x9b, 0x2c, 0x56, 0x06,
-  0x43, 0x86, 0xbf, 0x67, 0x24, 0x06, 0xd6, 0x62, 0x03, 0x95, 0xbe, 0x43,
-  0xf4, 0x6a, 0x4b, 0xfe, 0x2b, 0x0b, 0x38, 0xbe, 0x42, 0x2d, 0x6e, 0x64,
-  0x12, 0x6e, 0x4a, 0xcf, 0xf2, 0x51, 0x27, 0xb6, 0x64, 0xc5, 0xc9, 0xd5,
-  0x5b, 0xb3, 0xc1, 0x62, 0x94, 0x24, 0xc4, 0xee, 0x9d, 0xeb, 0xdd, 0x1d,
-  0x2a, 0xfd, 0xc3, 0x6b, 0x13, 0xf1, 0xbd, 0x89, 0xae, 0xbe, 0xd6, 0xf0,
-  0x57, 0x6c, 0x5d, 0x68, 0x3c, 0x1b, 0x7e, 0x2d, 0x5d, 0x53, 0xf7, 0xaf,
-  0x53, 0x30, 0x81, 0xde, 0x7a, 0x95, 0x62, 0x51, 0x9c, 0x91, 0x8e, 0xc8,
-  0xba, 0xe8, 0xea, 0xc7, 0x3a, 0x13, 0x0e, 0x2d, 0x81, 0x6b, 0x27, 0x5c,
-  0x63, 0xbd, 0x41, 0x67, 0x48, 0xd6, 0xb1, 0x2f, 0x6c, 0x6a, 0x54, 0xed,
-  0x59, 0x6f, 0x85, 0x81, 0x47, 0xb0, 0x84, 0xbc, 0xa9, 0xda, 0x7a, 0x00,
-  0xb1, 0xbf, 0x53, 0xda, 0x1c, 0xc1, 0x6f, 0x60, 0xd0, 0x08, 0x53, 0x41,
-  0xa6, 0xd3, 0x66, 0x2d, 0x2b, 0x97, 0xfc, 0xab, 0x91, 0x66, 0x73, 0xcd,
-  0x04, 0x1d, 0xe5, 0x25, 0x7c, 0xbc, 0x0c, 0xc2, 0xc4, 0x0a, 0xa5, 0x3d,
-  0x8a, 0xa3, 0xc3, 0x50, 0x2d, 0xa2, 0xa3, 0x09, 0x88, 0x9a, 0x37, 0xfd,
-  0xcd, 0x8d, 0x8e, 0xb6, 0xe4, 0xd6, 0xe9, 0xfa, 0x45, 0x59, 0x92, 0x05,
-  0xa2, 0xb4, 0x72, 0x02, 0x46, 0xe0, 0x8f, 0x9d, 0x80, 0x07, 0x17, 0xe5,
-  0x93, 0x8f, 0x90, 0x85, 0x98, 0x1e, 0x25, 0x8d, 0x29, 0xdf, 0x10, 0x36,
-  0x7b, 0x56, 0xd3, 0xcd, 0x3b, 0xe2, 0x9a, 0x4c, 0x72, 0x8d, 0xb4, 0x4d,
-  0xe9, 0x2c, 0xd2, 0x54, 0xf2, 0x0e, 0x7e, 0x90, 0x37, 0x2f, 0xef, 0xeb,
-  0x38, 0x7a, 0xf7, 0x8f, 0xcf, 0x1f, 0xbf, 0x8f, 0xe0, 0x29, 0x10, 0x39,
-  0x3e, 0xa2, 0x65, 0xfc, 0xee, 0x9f, 0x8f, 0x0f, 0xdf, 0x3f, 0x39, 0x8a,
-  0x8e, 0x12, 0x79, 0x2f, 0xd3, 0xf8, 0x4e, 0x55, 0x58, 0xa7, 0x92, 0x52,
-  0xa7, 0x82, 0x04, 0x27, 0x85, 0x91, 0x39, 0x7f, 0x56, 0xa8, 0x1c, 0xe2,
-  0xad, 0x58, 0x94, 0x8b, 0xb0, 0xeb, 0x62, 0xd4, 0x2e, 0x2f, 0x3f, 0xb6,
-  0x84, 0x12, 0xad, 0xdd, 0x09, 0x9e, 0xa4, 0x3b, 0xf6, 0xe3, 0x0f, 0xdf,
-  0x06, 0xe6, 0x77, 0xf3, 0xf7, 0x47, 0xf0, 0xfb, 0xef, 0x70, 0xec, 0xc9,
-  0xdb, 0x5f, 0x5b, 0x47, 0x6c, 0xa1, 0xef, 0xe2, 0x7c, 0x02, 0x9b, 0xe0,
-  0x0c, 0x69, 0xdd, 0x74, 0xfa, 0xf0, 0x15, 0x78, 0x92, 0x7d, 0x14, 0xe7,
-  0x47, 0x49, 0xdb, 0x62, 0x12, 0x1e, 0x27, 0xf0, 0xac, 0x25, 0xcd, 0xe1,
-  0x73, 0x88, 0xda, 0x71, 0x38, 0x82, 0x0b, 0x88, 0xa8, 0xaa, 0x44, 0x97,
-  0x43, 0x5d, 0x85, 0xca, 0x64, 0x9c, 0xb3, 0xa2, 0x51, 0x71, 0x7f, 0xcc,
-  0xeb, 0x74, 0x9c, 0xae, 0x26, 0x70, 0x1f, 0xb8, 0xd9, 0x59, 0x2b, 0xdd,
-  0x5b, 0xb5, 0x96, 0xba, 0x71, 0x74, 0x4c, 0xc3, 0xc0, 0x31, 0x3c, 0x41,
-  0xaa, 0x11, 0x09, 0x18, 0x58, 0x13, 0xef, 0x7a, 0xb9, 0xcf, 0x58, 0x38,
-  0xf2, 0x97, 0x27, 0x97, 0x2e, 0x2d, 0xe2, 0x68, 0x66, 0x3d, 0x8e, 0x7f,
-  0xb5, 0xba, 0xfa, 0xbc, 0x5a, 0x52, 0xf2, 0x5e, 0x09, 0x57, 0x24, 0x46,
-  0x60, 0xa2, 0xd6, 0x31, 0x82, 0x2b, 0xfa, 0xfa, 0xe5, 0xdb, 0x68, 0x42,
-  0x79, 0xbe, 0x76, 0x13, 0x38, 0x19, 0xd3, 0x95, 0x36, 0xa6, 0x73, 0xb4,
-  0x0d, 0x71, 0x74, 0x98, 0xcf, 0x91, 0x29, 0xe4, 0x36, 0xec, 0x9d, 0x8c,
-  0xec, 0x9d, 0xfa, 0xbd, 0x81, 0x54, 0xaf, 0x31, 0x46, 0xac, 0x66, 0x5e,
-  0x34, 0xcf, 0xbc, 0x21, 0x00, 0xc6, 0xb2, 0x20, 0x43, 0x30, 0xc4, 0x80,
-  0x91, 0xc7, 0x13, 0x38, 0xa5, 0xdd, 0xad, 0xd3, 0x16, 0xf6, 0x97, 0x38,
-  0x92, 0x1f, 0x07, 0x09, 0x7b, 0x74, 0x4b, 0xe8, 0x86, 0x24, 0xaa, 0xaa,
-  0xa4, 0x79, 0x8b, 0x2d, 0x8a, 0xd2, 0xf0, 0xe2, 0x4e, 0xa8, 0x9d, 0x5b,
-  0x0d, 0x31, 0xc5, 0xc1, 0x12, 0x82, 0x8f, 0x22, 0xaf, 0xe4, 0x23, 0x78,
-  0xd8, 0xe1, 0x82, 0x45, 0x53, 0xb9, 0xd1, 0x39, 0x64, 0x88, 0x08, 0x94,
-  0x60, 0x9d, 0x41, 0xfe, 0x68, 0xab, 0x67, 0x0f, 0xf7, 0xe1, 0x6f, 0xd7,
-  0xdf, 0xbf, 0x4e, 0x6a, 0x61, 0xac, 0x8c, 0x33, 0x36, 0x96, 0x7c, 0xec,
-  0x2c, 0x09, 0xa3, 0xc7, 0x27, 0xf6, 0x1c, 0x7c, 0xd9, 0xee, 0x5f, 0xc0,
-  0x01, 0x9a, 0x90, 0x25, 0x9e, 0x4a, 0x65, 0xec, 0x98, 0xbf, 0x81, 0x29,
-  0xd2, 0x65, 0x28, 0x5c, 0x91, 0xde, 0xde, 0x89, 0x25, 0x11, 0xef, 0xd8,
-  0x8c, 0xe8, 0xdb, 0xac, 0x94, 0xd1, 0x24, 0xac, 0x78, 0x84, 0xf1, 0xa5,
-  0xb4, 0xdb, 0xfe, 0x4a, 0xa8, 0x52, 0x66, 0x30, 0x85, 0x3b, 0xa3, 0x31,
-  0x0a, 0xa1, 0x9f, 0x0e, 0x09, 0x42, 0xc1, 0x87, 0x4a, 0x3b, 0xc8, 0x75,
-  0x53, 0x0d, 0x68, 0xba, 0xb5, 0x2f, 0xb4, 0xe3, 0x5d, 0x64, 0x3f, 0xf2,
-  0x54, 0xef, 0xdf, 0x65, 0x89, 0x47, 0xe0, 0x7b, 0xf6, 0x81, 0xf3, 0xe6,
-  0xb6, 0x77, 0x92, 0xc5, 0xd9, 0x36, 0x30, 0x07, 0x3d, 0xaa, 0xfd, 0xae,
-  0x8a, 0x3d, 0x7e, 0x0c, 0x41, 0x12, 0x5c, 0xc1, 0xbc, 0xb7, 0x5e, 0xc0,
-  0x79, 0x5f, 0xca, 0x6b, 0x89, 0x1c, 0x82, 0x1a, 0xab, 0xca, 0xe0, 0x35,
-  0x7b, 0x44, 0xbd, 0x3c, 0xb4, 0x7f, 0x52, 0xf3, 0x00, 0x5e, 0xac, 0xeb,
-  0x99, 0xb1, 0x55, 0x44, 0x48, 0x38, 0xef, 0x20, 0x80, 0xd7, 0xc2, 0x83,
-  0x3e, 0xe4, 0x7e, 0xaf, 0x2b, 0xc7, 0xce, 0x34, 0x32, 0xec, 0xf6, 0x61,
-  0x2d, 0x02, 0x35, 0x43, 0x2e, 0x68, 0x08, 0xae, 0x0d, 0xe4, 0xcf, 0xb7,
-  0xf2, 0x7d, 0x7d, 0x1c, 0x29, 0x7b, 0xfe, 0xb2, 0x37, 0xa6, 0x9c, 0xf0,
-  0x14, 0x3a, 0x81, 0x54, 0x94, 0x25, 0x7d, 0xcd, 0x4d, 0xc0, 0xa1, 0xe6,
-  0x5f, 0x50, 0xf5, 0x6e, 0x7d, 0xbf, 0x2f, 0x0c, 0xd7, 0xf6, 0xbf, 0xbf,
-  0xfa, 0xee, 0x1b, 0xe7, 0xea, 0x1f, 0x24, 0x36, 0x27, 0xeb, 0x62, 0x56,
-  0x85, 0xe7, 0x89, 0xae, 0x4a, 0x2d, 0x32, 0x59, 0x65, 0xbd, 0x4e, 0xb1,
-  0x35, 0x2f, 0x28, 0x88, 0x91, 0x96, 0xcd, 0x9f, 0x00, 0xbd, 0x1b, 0x69,
-  0x6b, 0x5d, 0x59, 0x49, 0xc1, 0x64, 0x71, 0x1f, 0x77, 0x84, 0x3a, 0x1f,
-  0x88, 0xff, 0x22, 0x74, 0x3a, 0x9f, 0x78, 0x78, 0x0c, 0x04, 0xd4, 0xb2,
-  0x8a, 0x83, 0x93, 0xad, 0xc7, 0x14, 0xea, 0x1d, 0xb3, 0xad, 0x74, 0xec,
-  0xcc, 0x37, 0x12, 0xcd, 0xc7, 0x10, 0xbe, 0x40, 0x84, 0xd6, 0x2e, 0x9a,
-  0x40, 0x24, 0xea, 0xba, 0x54, 0xbe, 0x35, 0xcd, 0xa8, 0x22, 0x46, 0x3b,
-  0x7c, 0x9d, 0x5d, 0x71, 0x88, 0x18, 0xb5, 0x99, 0x39, 0xd6, 0x96, 0x27,
-  0x6d, 0x25, 0xde, 0x55, 0x51, 0x65, 0xf1, 0x58, 0x49, 0xbb, 0xd1, 0xee,
-  0x45, 0x4d, 0x25, 0x8d, 0x84, 0xef, 0xc6, 0x9b, 0xda, 0x76, 0xd7, 0x06,
-  0x3d, 0x92, 0xb0, 0x6c, 0x11, 0x8c, 0x89, 0x14, 0xf6, 0xf9, 0x32, 0x8c,
-  0x14, 0x20, 0x3a, 0xef, 0xd5, 0xa0, 0xc0, 0x94, 0x94, 0xb2, 0xba, 0x71,
-  0x05, 0x62, 0xe6, 0xb8, 0xc3, 0x0c, 0x29, 0xea, 0x57, 0x26, 0x22, 0x1d,
-  0x42, 0x6e, 0x28, 0x5d, 0xaf, 0x7e, 0x95, 0xa9, 0x8b, 0x06, 0xa2, 0x88,
-  0xa2, 0x57, 0xdb, 0xf8, 0x28, 0xb1, 0xda, 0xb8, 0xb8, 0xcb, 0xa1, 0x98,
-  0xc0, 0x8a, 0x99, 0xbb, 0x86, 0xb6, 0x4a, 0x8c, 0xb5, 0x0a, 0xa6, 0x20,
-  0xda, 0x97, 0x20, 0x27, 0xd8, 0x43, 0xa1, 0xd1, 0xb5, 0xa5, 0x12, 0xbd,
-  0xd0, 0x35, 0xc9, 0xb9, 0xf2, 0xe3, 0x11, 0x88, 0x70, 0x6f, 0xdb, 0x09,
-  0x8c, 0xcf, 0x22, 0x66, 0xcb, 0xb5, 0x81, 0x98, 0x78, 0x15, 0x72, 0x1e,
-  0x5f, 0xe2, 0x63, 0xd1, 0x46, 0x98, 0x23, 0x72, 0x09, 0x4f, 0x9f, 0xaa,
-  0xce, 0x14, 0x52, 0xf0, 0x74, 0x47, 0x03, 0xd5, 0x7e, 0xa2, 0x7e, 0xa7,
-  0xde, 0x27, 0x68, 0x53, 0x86, 0xcb, 0x68, 0xa0, 0xe2, 0xa3, 0x7f, 0x88,
-  0xda, 0x17, 0x86, 0x6f, 0xde, 0xbe, 0xfa, 0x0e, 0x96, 0x64, 0x2b, 0x9f,
-  0x8b, 0x15, 0xb5, 0x79, 0xb1, 0x2a, 0xbb, 0x09, 0x8b, 0x4f, 0x9c, 0xbe,
-  0x41, 0x0c, 0x50, 0x36, 0x19, 0x9a, 0x1d, 0x87, 0xae, 0x52, 0x84, 0xdf,
-  0x07, 0x64, 0x68, 0x89, 0x86, 0x9d, 0x87, 0xa8, 0xfa, 0x9d, 0xeb, 0xb5,
-  0x0e, 0x25, 0xd9, 0xfa, 0x7a, 0x3c, 0xd2, 0xbb, 0xf6, 0x8c, 0xe8, 0x3a,
-  0xe4, 0x8b, 0x7a, 0x02, 0xe7, 0xa4, 0x73, 0xbc, 0x52, 0x78, 0xeb, 0xe4,
-  0xed, 0x04, 0xa5, 0x99, 0x54, 0xf6, 0x06, 0x88, 0x76, 0x87, 0x30, 0x2f,
-  0xea, 0x4f, 0x27, 0x99, 0x25, 0x0f, 0x44, 0x1d, 0x3c, 0xda, 0xe9, 0x27,
-  0x0a, 0x7f, 0x6d, 0xe1, 0x9b, 0xd4, 0xb5, 0x7d, 0x0a, 0x2c, 0xef, 0x0d,
-  0x9d, 0xba, 0x4e, 0x45, 0x45, 0xfa, 0x43, 0x8e, 0x6d, 0x34, 0x16, 0x23,
-  0xef, 0xcd, 0x30, 0x48, 0xac, 0x63, 0xa8, 0x9b, 0x6d, 0x7a, 0x58, 0xf7,
-  0x2b, 0x51, 0x35, 0xa2, 0x84, 0x97, 0x95, 0x33, 0x9b, 0xe8, 0x8f, 0xc2,
-  0xc4, 0xba, 0x43, 0x5d, 0x1a, 0x3a, 0x20, 0x85, 0x49, 0x0b, 0xbc, 0x8c,
-  0xe4, 0xc5, 0x36, 0x41, 0x08, 0x55, 0x96, 0xd8, 0x47, 0x07, 0xf7, 0x82,
-  0x21, 0x9c, 0x02, 0x24, 0x21, 0x10, 0x5f, 0x51, 0x64, 0x2a, 0x94, 0x3b,
-  0x40, 0xfd, 0x83, 0x33, 0x9e, 0xff, 0x2c, 0x78, 0x68, 0xbc, 0xf3, 0x95,
-  0x89, 0x26, 0xca, 0x9d, 0xb2, 0xc5, 0xc3, 0xba, 0xaf, 0xf3, 0x3b, 0xf5,
-  0x78, 0xeb, 0x76, 0x29, 0x1d, 0xb8, 0xf6, 0xc3, 0x0c, 0x4f, 0xbb, 0x2f,
-  0x87, 0x38, 0xf2, 0x9b, 0x1c, 0xe3, 0x3f, 0x97, 0xde, 0x87, 0xb2, 0xbb,
-  0xfb, 0x69, 0x43, 0x24, 0x85, 0xa8, 0x6e, 0xe4, 0x78, 0x83, 0x78, 0xb4,
-  0xcd, 0x6f, 0xd2, 0x7e, 0x37, 0xf7, 0x3f, 0x8c, 0x78, 0x93, 0xd3, 0xda,
-  0x09, 0xc7, 0xcf, 0x47, 0x3c, 0x63, 0xe5, 0x43, 0xc1, 0xfd, 0x66, 0xeb,
-  0x99, 0x47, 0x46, 0xcf, 0xe3, 0x24, 0x5c, 0x2c, 0x95, 0xc7, 0x21, 0x30,
-  0x47, 0x40, 0x9c, 0x07, 0x38, 0xe7, 0x1e, 0x6c, 0x43, 0x0b, 0xb0, 0x98,
-  0x6d, 0x3f, 0x12, 0x17, 0x33, 0xfe, 0x9b, 0x15, 0xbd, 0xf2, 0x3f, 0xef,
-  0xfd, 0x07, 0xb4, 0xda, 0xa2, 0xb2, 0xf8, 0x1b, 0x00, 0x00
+  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x9d, 0x19,
+  0xe7, 0x7a, 0xe3, 0x36, 0xf2, 0xb7, 0xf3, 0x14, 0x63, 0x79, 0xcf, 0xa4,
+  0x77, 0x25, 0xca, 0x35, 0xc5, 0x2a, 0xe9, 0xbd, 0xc7, 0xce, 0xb5, 0x6d,
+  0x1f, 0x44, 0x82, 0x22, 0xb2, 0x14, 0xc1, 0x03, 0x40, 0x97, 0x4b, 0xfc,
+  0xee, 0x37, 0xc3, 0x21, 0x44, 0x51, 0xf4, 0x29, 0xc5, 0x4d, 0xc4, 0x60,
+  0x7a, 0xe7, 0xee, 0x74, 0xff, 0x93, 0xef, 0x3f, 0xbe, 0xfe, 0xd7, 0x0f,
+  0x9f, 0x42, 0xe6, 0x56, 0xf9, 0xfc, 0xad, 0x29, 0x7f, 0xe0, 0xa7, 0x14,
+  0xc9, 0xfc, 0xad, 0xbd, 0xe9, 0x4a, 0x3a, 0x01, 0x85, 0x58, 0xc9, 0x59,
+  0x70, 0xa3, 0xe4, 0x6d, 0xa9, 0x8d, 0x0b, 0x20, 0xd6, 0x85, 0x93, 0x85,
+  0x9b, 0x05, 0xb7, 0x2a, 0x71, 0xd9, 0x2c, 0x91, 0x37, 0x2a, 0x96, 0xa3,
+  0xfa, 0x30, 0x04, 0x55, 0x28, 0xa7, 0x44, 0x3e, 0xb2, 0xb1, 0xc8, 0xe5,
+  0xec, 0x24, 0x3a, 0x0e, 0x88, 0x8f, 0x53, 0x2e, 0x97, 0xf3, 0x7f, 0xa8,
+  0xcf, 0x14, 0x7c, 0xa3, 0x97, 0xaa, 0x98, 0x8e, 0x19, 0x82, 0x57, 0xd6,
+  0xdd, 0xe7, 0x12, 0xdc, 0x7d, 0x29, 0x67, 0x4e, 0xde, 0xb9, 0x71, 0x6c,
+  0x2d, 0x82, 0xf7, 0x9e, 0xc2, 0xaf, 0xf8, 0x77, 0x6f, 0x25, 0x0c, 0xa2,
+  0x5f, 0xc2, 0xf1, 0x84, 0x4e, 0xa5, 0x48, 0x12, 0x55, 0x2c, 0x9b, 0xe3,
+  0x03, 0xfe, 0xe2, 0x0f, 0xe9, 0x3c, 0xc4, 0xcf, 0x85, 0x4e, 0xee, 0x99,
+  0x28, 0x93, 0x6a, 0x99, 0xb9, 0x4b, 0x38, 0x39, 0x3e, 0xfe, 0x5b, 0x4d,
+  0x97, 0xa2, 0xc6, 0xa3, 0x54, 0xac, 0x54, 0x7e, 0x7f, 0x09, 0x56, 0x14,
+  0x76, 0x64, 0xa5, 0x51, 0x69, 0x7d, 0x47, 0x42, 0x47, 0x22, 0x57, 0x4b,
+  0x94, 0x12, 0x4b, 0xb4, 0xcc, 0xd4, 0xe0, 0x85, 0x88, 0xdf, 0x2c, 0x8d,
+  0xae, 0x8a, 0xe4, 0x12, 0x0e, 0xce, 0xcf, 0xcf, 0x93, 0xf3, 0xf3, 0x0d,
+  0x99, 0x07, 0x8d, 0x0f, 0x58, 0x5e, 0xa9, 0x2d, 0x1a, 0xad, 0x91, 0x81,
+  0x58, 0x58, 0x9d, 0x57, 0x4e, 0x32, 0x67, 0x5d, 0x7a, 0xc5, 0x0d, 0x2b,
+  0xc4, 0x87, 0x85, 0x76, 0x4e, 0xaf, 0xfc, 0x29, 0x97, 0xe9, 0xfa, 0xa6,
+  0xf6, 0xe1, 0x25, 0x9c, 0x9d, 0x1e, 0x97, 0x77, 0x93, 0x4d, 0x4b, 0xce,
+  0xdf, 0xf5, 0x10, 0xef, 0x10, 0x51, 0x39, 0xbd, 0xa1, 0x90, 0x2a, 0xca,
+  0xca, 0xd5, 0x5e, 0xa8, 0x90, 0x79, 0x41, 0x4f, 0x56, 0xe6, 0x32, 0x6e,
+  0x34, 0x1c, 0xdd, 0xca, 0xc5, 0x1b, 0x85, 0x76, 0x96, 0xa5, 0x14, 0x46,
+  0x14, 0xb1, 0xbc, 0x84, 0x42, 0x17, 0xb2, 0xd1, 0xc7, 0x24, 0xd2, 0x8c,
+  0x8c, 0x48, 0x54, 0x65, 0xbb, 0xbe, 0x4d, 0x95, 0xcc, 0x13, 0x2b, 0x99,
+  0x4b, 0x83, 0xd8, 0x9a, 0x71, 0x37, 0xb2, 0x99, 0x48, 0xf4, 0x2d, 0x42,
+  0xf0, 0xfb, 0xe4, 0xa2, 0xbc, 0x83, 0x13, 0xfc, 0x35, 0xcb, 0x85, 0x08,
+  0x8f, 0x87, 0xc0, 0x3f, 0xd1, 0xf9, 0x51, 0x8b, 0xae, 0xfe, 0x5b, 0x87,
+  0xaf, 0x91, 0x88, 0xa0, 0x6e, 0x58, 0xc9, 0x6e, 0x38, 0xc3, 0x3f, 0xfd,
+  0x10, 0xa4, 0x69, 0xca, 0xf6, 0xab, 0x62, 0xc4, 0x5e, 0x61, 0x3f, 0x75,
+  0xbd, 0x32, 0x42, 0xf9, 0xdb, 0x5e, 0xe9, 0xea, 0x4e, 0x0a, 0x62, 0x8c,
+  0x54, 0x02, 0x07, 0x71, 0x1c, 0x6f, 0x10, 0x8f, 0x7c, 0x58, 0x4e, 0x98,
+  0xa9, 0x8f, 0x86, 0xcf, 0xa2, 0x9d, 0x16, 0xc4, 0x3a, 0xd7, 0x06, 0xb5,
+  0x3c, 0x3d, 0x3d, 0x5d, 0x27, 0x1c, 0x52, 0xbe, 0x8d, 0xc2, 0x56, 0xba,
+  0xd0, 0xb6, 0x14, 0xb1, 0xec, 0x98, 0x8a, 0xde, 0xea, 0x68, 0xea, 0x83,
+  0xb5, 0x93, 0xb8, 0x75, 0xc8, 0xa8, 0x11, 0xe8, 0x30, 0x96, 0x78, 0x6f,
+  0x64, 0xe1, 0x76, 0xb2, 0xe7, 0xac, 0x60, 0xf6, 0x4c, 0xea, 0x3d, 0xda,
+  0x89, 0x6a, 0x3f, 0x19, 0xce, 0xca, 0xc6, 0xc0, 0xca, 0x58, 0xa2, 0x2a,
+  0xb5, 0x5a, 0x97, 0x48, 0xa2, 0x6c, 0x99, 0x8b, 0x7b, 0x74, 0x46, 0xae,
+  0xe3, 0x37, 0xdb, 0x76, 0x3f, 0x56, 0x66, 0x89, 0x8c, 0xb5, 0x11, 0x5c,
+  0x2a, 0x9c, 0x7e, 0x1d, 0x9d, 0x29, 0xfa, 0x17, 0x8f, 0x05, 0xff, 0xec,
+  0x64, 0x71, 0x7e, 0xf1, 0xce, 0x76, 0x50, 0x7a, 0xf6, 0x5d, 0xa6, 0x3a,
+  0xae, 0xec, 0xb0, 0x3d, 0x67, 0xfa, 0x46, 0x1a, 0xb2, 0xba, 0x9f, 0xad,
+  0xc7, 0x70, 0x8a, 0xd2, 0xc8, 0x09, 0x43, 0x3e, 0x93, 0xa9, 0xad, 0xa4,
+  0xb6, 0xbb, 0x9c, 0xb5, 0x41, 0xa1, 0xe8, 0x4b, 0x36, 0xaf, 0x13, 0xf5,
+  0xb7, 0xdf, 0x7e, 0xbb, 0x9f, 0x48, 0x9c, 0xcd, 0x9b, 0x9c, 0xce, 0xbb,
+  0xfe, 0xf7, 0xe9, 0xd7, 0xda, 0xdf, 0xc5, 0x8f, 0x2a, 0xa7, 0x72, 0xe5,
+  0xee, 0x1b, 0xf9, 0xb9, 0x16, 0xe8, 0xda, 0xba, 0x91, 0xb0, 0xf0, 0x5c,
+  0x0a, 0x64, 0x83, 0xc2, 0xb2, 0x46, 0xf8, 0xdd, 0xa8, 0x71, 0xce, 0x3b,
+  0x17, 0xe4, 0x9b, 0xae, 0xce, 0x67, 0x65, 0x3f, 0x53, 0x5b, 0x9d, 0x59,
+  0xf8, 0x76, 0x97, 0xad, 0x0b, 0xba, 0x5f, 0x8d, 0x5e, 0xf7, 0x9e, 0xa6,
+  0xde, 0xff, 0x2d, 0xe4, 0x2f, 0x44, 0xa0, 0xcb, 0xfa, 0x20, 0x31, 0xba,
+  0x44, 0x92, 0x62, 0x48, 0x87, 0xf4, 0x94, 0x3f, 0xce, 0xea, 0x8f, 0xc5,
+  0x9b, 0x53, 0xe6, 0xec, 0x13, 0xd1, 0xe7, 0x54, 0x8f, 0x78, 0xbb, 0x4d,
+  0x1b, 0x99, 0x0b, 0xa7, 0x6e, 0xe4, 0xa3, 0x65, 0x4e, 0x1a, 0xa3, 0xb7,
+  0x6f, 0xb9, 0xc7, 0x76, 0xda, 0xf0, 0x05, 0x76, 0x8f, 0x5d, 0x2d, 0xc3,
+  0xcb, 0x15, 0x65, 0xae, 0xec, 0xae, 0xe1, 0xd0, 0x93, 0xda, 0x9f, 0x59,
+  0x4e, 0x97, 0x9d, 0x11, 0xd1, 0x1b, 0x1e, 0x3b, 0xba, 0x5a, 0x6f, 0xe6,
+  0xf5, 0x9a, 0x50, 0xaf, 0xe2, 0x5a, 0xdd, 0x8d, 0xd1, 0xb7, 0xdd, 0x4c,
+  0x7d, 0xf7, 0xdd, 0x77, 0x27, 0x3b, 0x4c, 0x69, 0x86, 0xdb, 0xbb, 0xcc,
+  0x87, 0x15, 0x3f, 0xd9, 0xe2, 0xaa, 0x98, 0x63, 0x7f, 0xd8, 0x36, 0x48,
+  0xd3, 0x71, 0xbd, 0x07, 0xe0, 0x0a, 0x32, 0xe6, 0xdd, 0xe3, 0xad, 0x29,
+  0xcd, 0x73, 0x5a, 0x10, 0x12, 0x75, 0x03, 0x2a, 0x99, 0x35, 0x13, 0x97,
+  0x76, 0x83, 0xa9, 0x1f, 0x4b, 0x74, 0xf0, 0x08, 0xcd, 0x1e, 0xf2, 0x65,
+  0x32, 0x9f, 0x8e, 0x11, 0xd2, 0xb9, 0x4a, 0x4f, 0xf0, 0x48, 0xe7, 0xec,
+  0x6c, 0xfe, 0xb1, 0x2e, 0x0a, 0x6a, 0xb5, 0x8c, 0x0e, 0x4e, 0xc3, 0xbd,
+  0xae, 0x0c, 0xfc, 0x43, 0x8d, 0x3e, 0x53, 0x28, 0xfc, 0xac, 0xc1, 0x4c,
+  0xb5, 0x59, 0x81, 0x88, 0xc9, 0xdc, 0xd9, 0x60, 0x8c, 0xb2, 0x6e, 0x55,
+  0xaa, 0x06, 0xb0, 0x92, 0x2e, 0xd3, 0xc9, 0x6c, 0xf0, 0xc3, 0xf7, 0x57,
+  0xd7, 0x03, 0x42, 0x25, 0x5c, 0xee, 0x36, 0x24, 0xa8, 0x40, 0x3c, 0x6d,
+  0xde, 0x58, 0xde, 0x67, 0x1a, 0x78, 0x9c, 0x0b, 0x6b, 0x67, 0x4d, 0x45,
+  0xa0, 0x76, 0x0c, 0xf6, 0xc4, 0x5e, 0x7b, 0x4e, 0x55, 0x02, 0x33, 0x1c,
+  0xc3, 0x55, 0xb3, 0xac, 0xe3, 0x31, 0x3f, 0x3c, 0xb8, 0x3b, 0xbd, 0x58,
+  0xc4, 0x93, 0xe9, 0x98, 0xe0, 0x2d, 0x12, 0x8f, 0x0d, 0x44, 0xe3, 0x94,
+  0xe3, 0x5d, 0x8d, 0x9f, 0x51, 0x12, 0x5f, 0x7b, 0x49, 0xec, 0x16, 0x7e,
+  0xe6, 0xc9, 0x88, 0x74, 0xd6, 0xaa, 0x84, 0xa9, 0xc8, 0xc0, 0xd7, 0x74,
+  0x6c, 0x97, 0xb1, 0xba, 0x02, 0x62, 0x6d, 0x0c, 0x72, 0x99, 0xe9, 0x34,
+  0xe5, 0xb3, 0x28, 0x95, 0x13, 0x39, 0xb6, 0x95, 0x19, 0xd5, 0x1b, 0x60,
+  0xe9, 0xc5, 0x32, 0xd3, 0x39, 0x26, 0xe2, 0x2c, 0xa8, 0xdd, 0x08, 0xdf,
+  0x21, 0xbf, 0x00, 0xc6, 0x5d, 0x61, 0xad, 0x90, 0x12, 0xfd, 0x81, 0x6e,
+  0x6a, 0x04, 0xf9, 0xd3, 0x1f, 0x12, 0xc6, 0x38, 0xab, 0x32, 0x97, 0x4e,
+  0x12, 0x52, 0x47, 0xfa, 0x0f, 0x0d, 0xa7, 0x56, 0xf2, 0xfe, 0x68, 0x04,
+  0xff, 0xd2, 0x15, 0xc4, 0xe8, 0x4b, 0x4c, 0x7a, 0xa8, 0x35, 0xb1, 0x90,
+  0x49, 0x83, 0xac, 0x8a, 0x04, 0x32, 0x71, 0x23, 0xc1, 0x65, 0x72, 0x05,
+  0xa5, 0x2e, 0xa1, 0x2a, 0x11, 0x81, 0xd3, 0x21, 0xaf, 0x04, 0xc4, 0x3a,
+  0xa1, 0x4b, 0xa3, 0xab, 0x65, 0x46, 0x48, 0x90, 0xaa, 0x5c, 0x82, 0xac,
+  0x2c, 0x1a, 0x60, 0xc4, 0xca, 0x46, 0x84, 0x34, 0x1a, 0x75, 0xac, 0x64,
+  0x93, 0x06, 0xb6, 0x5a, 0xac, 0x94, 0x1b, 0xc0, 0x8d, 0xc8, 0x2b, 0x3c,
+  0x5e, 0xa1, 0x98, 0x01, 0x2a, 0xc5, 0x61, 0xa0, 0xd4, 0xe2, 0xf4, 0xec,
+  0x27, 0xea, 0xa9, 0x4f, 0xd4, 0x93, 0xf9, 0x55, 0x15, 0xc7, 0xd2, 0xda,
+  0x7d, 0x4c, 0x4a, 0x9f, 0xbe, 0x0d, 0x96, 0xc2, 0xa3, 0x4f, 0x67, 0xb4,
+  0xce, 0xf8, 0x5c, 0xce, 0x84, 0x05, 0xcb, 0x54, 0x69, 0x95, 0xe7, 0xf7,
+  0x10, 0x73, 0xae, 0x4b, 0xf4, 0xb4, 0xae, 0x2d, 0xe0, 0xf0, 0x34, 0x59,
+  0x1a, 0x4d, 0x17, 0x06, 0x5d, 0x85, 0x7f, 0xc7, 0xc4, 0x06, 0x56, 0xe2,
+  0x1e, 0x0a, 0xac, 0xfd, 0x38, 0xd7, 0x96, 0x0c, 0x57, 0x16, 0x70, 0x6d,
+  0x84, 0x52, 0x2c, 0x65, 0xe4, 0x2b, 0xa3, 0xa3, 0x74, 0x5f, 0x7d, 0x8f,
+  0x93, 0x9d, 0xce, 0xaf, 0xcd, 0x3d, 0xf6, 0x98, 0x28, 0x22, 0x52, 0x6f,
+  0x55, 0x5b, 0x28, 0xd4, 0xbb, 0xfb, 0x35, 0x12, 0x34, 0x45, 0x12, 0xcc,
+  0x3f, 0xd7, 0xf0, 0x11, 0x0e, 0x1c, 0xd2, 0x9b, 0x75, 0xbe, 0x92, 0xae,
+  0x2a, 0x3b, 0xb5, 0xe3, 0xc5, 0xe3, 0x43, 0xdb, 0x0f, 0x48, 0xf6, 0x39,
+  0x09, 0x08, 0xac, 0x0b, 0xe6, 0x3f, 0x97, 0x89, 0x70, 0xa8, 0x05, 0x5c,
+  0x39, 0xe1, 0x2a, 0xcb, 0xca, 0x9c, 0x23, 0x96, 0xa7, 0x9d, 0xda, 0xd8,
+  0xa8, 0xb2, 0xa6, 0xbb, 0x11, 0x06, 0x9e, 0xc0, 0x0c, 0xd2, 0xaa, 0xa8,
+  0xab, 0x1e, 0x42, 0xae, 0x1e, 0x6d, 0x8e, 0xe0, 0x57, 0x30, 0x28, 0xde,
+  0x14, 0x90, 0xe8, 0xb8, 0x5a, 0xc9, 0xc2, 0x45, 0xff, 0xa9, 0xa4, 0xb9,
+  0xbf, 0x6a, 0x10, 0x5a, 0xcc, 0x09, 0x3c, 0x4c, 0x1a, 0x5e, 0x62, 0x81,
+  0xcc, 0x9e, 0x84, 0xc1, 0x81, 0xef, 0x09, 0xc1, 0xd1, 0x10, 0x44, 0xd9,
+  0x00, 0xb9, 0x44, 0x83, 0x23, 0x8f, 0x6d, 0x9d, 0x2e, 0x3f, 0xcc, 0x73,
+  0x92, 0x2f, 0x72, 0x2b, 0x87, 0x60, 0x04, 0xfe, 0xda, 0x21, 0x70, 0x26,
+  0x51, 0x08, 0xf9, 0x0a, 0x5b, 0x2e, 0x92, 0x3c, 0x89, 0x2a, 0x93, 0xff,
+  0x40, 0x59, 0xd8, 0xd1, 0x98, 0x4a, 0xec, 0x88, 0x3b, 0x2d, 0x31, 0x35,
+  0xd2, 0x56, 0xb9, 0xb3, 0x88, 0x52, 0xc8, 0x5b, 0xf8, 0x49, 0x2e, 0x3f,
+  0xbd, 0x2b, 0xc3, 0xe0, 0xf9, 0x8b, 0xf7, 0x0f, 0x5f, 0x06, 0xf0, 0x0c,
+  0x08, 0x1b, 0x3f, 0x82, 0x59, 0xf8, 0xfc, 0xd5, 0xe1, 0xc1, 0xcb, 0xa7,
+  0x47, 0xc1, 0x51, 0x24, 0xef, 0x64, 0x1c, 0xde, 0xaa, 0x02, 0x5b, 0x51,
+  0x94, 0xeb, 0x58, 0x10, 0xdf, 0x28, 0x33, 0x32, 0xe5, 0x25, 0x5e, 0xa5,
+  0x10, 0xae, 0xb9, 0x22, 0x5b, 0xcc, 0xb2, 0xd6, 0x3b, 0xf5, 0x71, 0xf2,
+  0x40, 0x78, 0x12, 0x15, 0xdd, 0xf0, 0x9a, 0xa4, 0x52, 0xfa, 0xf9, 0xa7,
+  0x2f, 0x3d, 0xed, 0xf3, 0x93, 0x97, 0x47, 0xf0, 0xdb, 0x6f, 0x70, 0x5c,
+  0x63, 0xd3, 0xef, 0xda, 0x06, 0x9b, 0xe9, 0xdb, 0x30, 0x1d, 0xc2, 0x3d,
+  0xf2, 0xf5, 0x12, 0xef, 0x5b, 0x59, 0xf8, 0x08, 0xbc, 0x50, 0x3e, 0x09,
+  0xd3, 0xa3, 0xa8, 0x1e, 0x1a, 0x11, 0xcf, 0x7f, 0xba, 0xaa, 0x31, 0x53,
+  0x78, 0x1f, 0x82, 0x7a, 0x27, 0x0d, 0xe0, 0x12, 0x02, 0xea, 0x1b, 0xc1,
+  0x64, 0x5b, 0x4e, 0xa6, 0x12, 0x89, 0x1c, 0x48, 0xc8, 0xe3, 0xbc, 0xfe,
+  0x1f, 0xa1, 0xd3, 0x61, 0xbc, 0x18, 0xc2, 0x5d, 0x43, 0xda, 0x98, 0x68,
+  0xa5, 0xbb, 0x56, 0x2b, 0xa9, 0x2b, 0x47, 0xb7, 0x34, 0xc5, 0x8f, 0xe1,
+  0x29, 0x22, 0xf5, 0xc8, 0xd1, 0x95, 0x26, 0xdc, 0xb0, 0x6d, 0xbf, 0x89,
+  0xfc, 0x11, 0x02, 0x10, 0x4d, 0xba, 0x38, 0x0b, 0x83, 0xb1, 0xe5, 0x7c,
+  0xfd, 0xc5, 0xea, 0xe2, 0xfd, 0x62, 0x46, 0xc1, 0xfa, 0x56, 0xb8, 0x2c,
+  0x32, 0x02, 0x03, 0xb3, 0x0a, 0x31, 0x91, 0x82, 0xcf, 0x3f, 0xbd, 0x0e,
+  0x86, 0x14, 0xd7, 0x2b, 0x37, 0x84, 0xd3, 0xbe, 0x9c, 0xb8, 0x32, 0x6b,
+  0xf3, 0x6a, 0x9f, 0x06, 0x07, 0xe9, 0x09, 0x52, 0x34, 0x81, 0xf4, 0xa0,
+  0xd3, 0x3e, 0xe8, 0x8c, 0x40, 0x3d, 0x86, 0x2c, 0x2a, 0xc4, 0x8c, 0x4c,
+  0x98, 0x2b, 0x2f, 0xa0, 0xde, 0x68, 0x63, 0x99, 0x89, 0xc1, 0xbc, 0x20,
+  0x17, 0x91, 0x99, 0x43, 0x38, 0x43, 0xa0, 0x37, 0xd4, 0xc2, 0xfe, 0x0c,
+  0x57, 0xe2, 0xe3, 0x86, 0x7a, 0x8f, 0xaa, 0x80, 0x2a, 0x20, 0x52, 0x45,
+  0x21, 0xcd, 0x35, 0x4e, 0x1b, 0xf2, 0xf9, 0x87, 0xb7, 0x42, 0x6d, 0x54,
+  0x2c, 0x84, 0x64, 0xbb, 0xa5, 0x2c, 0x3d, 0x0a, 0x6a, 0x01, 0x0f, 0xc0,
+  0xb9, 0x85, 0xcf, 0xcc, 0x97, 0xba, 0x88, 0x4e, 0x21, 0xc1, 0xc8, 0x23,
+  0xbd, 0x75, 0x06, 0xa9, 0x03, 0x2f, 0x64, 0x0f, 0xc1, 0xf0, 0xd5, 0xd5,
+  0xf7, 0xdf, 0x45, 0xa5, 0x30, 0x56, 0x86, 0x09, 0x6b, 0x89, 0x96, 0xad,
+  0x75, 0xf0, 0x6b, 0xc3, 0x96, 0x26, 0x83, 0x4f, 0x6a, 0xf8, 0x25, 0x0c,
+  0x50, 0x78, 0x12, 0x31, 0x96, 0x4a, 0xc8, 0x9e, 0xa6, 0xba, 0x62, 0xc4,
+  0x4a, 0x90, 0xaf, 0x22, 0x89, 0x1b, 0x70, 0x4b, 0xe4, 0xcf, 0x59, 0x7c,
+  0xf0, 0x65, 0x92, 0xcb, 0x60, 0xd8, 0x1c, 0x9a, 0xd5, 0x83, 0xdb, 0xe2,
+  0x1a, 0xfa, 0x99, 0x50, 0xb9, 0x4c, 0x60, 0x04, 0xb7, 0x46, 0xa3, 0xe1,
+  0x7e, 0x1c, 0xf6, 0xee, 0x7d, 0xdb, 0x86, 0x42, 0x3b, 0x48, 0x75, 0x55,
+  0x6c, 0xa1, 0xb4, 0x47, 0xee, 0x98, 0x8f, 0x4f, 0x82, 0xfd, 0xa0, 0x46,
+  0x7a, 0xf9, 0x3c, 0x89, 0x38, 0xc9, 0x5e, 0xb2, 0xea, 0x1c, 0x23, 0xb7,
+  0xae, 0x34, 0x66, 0x65, 0x6b, 0x57, 0x0c, 0x36, 0x50, 0xf6, 0xdb, 0x86,
+  0x74, 0x78, 0x08, 0x9e, 0x09, 0xcc, 0xe1, 0xa4, 0x73, 0x9e, 0xc2, 0x45,
+  0x87, 0xc5, 0x77, 0x12, 0x09, 0x04, 0xcd, 0x43, 0x95, 0xc0, 0x77, 0x8d,
+  0x21, 0x34, 0x81, 0xfd, 0xcc, 0xf6, 0x32, 0x1e, 0x4d, 0x0b, 0xeb, 0x36,
+  0x34, 0xf0, 0x32, 0xea, 0x80, 0x5f, 0xac, 0x23, 0x8d, 0x09, 0xcf, 0x09,
+  0xdd, 0x84, 0x78, 0xaf, 0x6d, 0xa9, 0xce, 0x54, 0x92, 0x80, 0xbd, 0xa4,
+  0x15, 0x8c, 0xeb, 0x93, 0xca, 0x73, 0xf7, 0x16, 0x6d, 0xf3, 0x3e, 0xf1,
+  0xbc, 0xeb, 0x1e, 0xd7, 0x6b, 0x5d, 0x5c, 0xbc, 0xd8, 0x98, 0x87, 0xcd,
+  0x9a, 0x38, 0x84, 0x58, 0xe4, 0x39, 0xbd, 0x38, 0x0d, 0xc1, 0xa1, 0xcc,
+  0xd7, 0x28, 0x74, 0xa3, 0x3d, 0xdf, 0x65, 0xa6, 0x69, 0xcd, 0xff, 0xfc,
+  0xf6, 0x9b, 0x2f, 0x9c, 0x2b, 0x7f, 0x92, 0x38, 0x56, 0xac, 0x0b, 0x59,
+  0x0a, 0x5e, 0x47, 0xba, 0xc8, 0xb5, 0x48, 0x64, 0x91, 0x74, 0xda, 0xbc,
+  0xd7, 0xcb, 0x73, 0x0f, 0x09, 0x95, 0xd5, 0x1e, 0x02, 0x3d, 0x1b, 0x69,
+  0x4b, 0x5d, 0x58, 0x49, 0xee, 0x63, 0x66, 0x0f, 0x2d, 0x47, 0xc7, 0xd6,
+  0xef, 0xe6, 0x38, 0x3a, 0x19, 0x72, 0x1e, 0x6c, 0x51, 0x97, 0xb2, 0x08,
+  0xbd, 0x71, 0x64, 0x69, 0xed, 0xdb, 0x56, 0x5f, 0x2b, 0x5d, 0x63, 0xc4,
+  0x17, 0x12, 0xf5, 0x46, 0xaf, 0x7d, 0x88, 0x49, 0x58, 0xba, 0x00, 0x3b,
+  0x96, 0x28, 0xcb, 0x5c, 0xf1, 0x44, 0x19, 0x53, 0x63, 0x0b, 0x5a, 0xb2,
+  0x56, 0xa5, 0xd0, 0xfb, 0x89, 0xc6, 0xc3, 0x09, 0x36, 0x8b, 0xa7, 0x75,
+  0x2f, 0xdd, 0x10, 0x50, 0x24, 0x61, 0xbf, 0x39, 0x2d, 0xb5, 0xfb, 0xb0,
+  0xa4, 0xe6, 0x44, 0x8c, 0x37, 0x5c, 0x4c, 0x43, 0x76, 0x3d, 0xb8, 0x38,
+  0x63, 0xb0, 0x05, 0x51, 0xa6, 0x12, 0x22, 0xec, 0x37, 0xc9, 0xde, 0x6f,
+  0x27, 0x74, 0xdd, 0xe9, 0x28, 0x9e, 0x26, 0xca, 0x65, 0xb1, 0x74, 0x19,
+  0xa6, 0xc7, 0xf1, 0x3a, 0x3d, 0x48, 0x4a, 0xb7, 0xcf, 0x10, 0x66, 0x2f,
+  0xb7, 0xfa, 0xbc, 0xf5, 0xe2, 0x17, 0x19, 0xbb, 0x60, 0x9b, 0x11, 0x21,
+  0x74, 0xfa, 0x14, 0xc1, 0x23, 0xab, 0x8d, 0x0b, 0xdb, 0x90, 0x89, 0x21,
+  0x2c, 0x3c, 0xa1, 0x9f, 0x42, 0x8b, 0xc8, 0x58, 0xab, 0x60, 0x04, 0xa2,
+  0x7e, 0x68, 0x78, 0x90, 0x22, 0x8d, 0x3f, 0x74, 0x69, 0x01, 0xe5, 0x4e,
+  0x75, 0x49, 0x4c, 0xe6, 0xbc, 0xc0, 0x80, 0xf0, 0x15, 0x59, 0x2f, 0x48,
+  0xcd, 0x1d, 0xb6, 0x5b, 0xf8, 0x9d, 0x2f, 0xe2, 0x68, 0xa5, 0x2c, 0x90,
+  0xe5, 0xaf, 0x0f, 0x2c, 0x24, 0xd5, 0x06, 0x42, 0x82, 0x2b, 0x04, 0x1e,
+  0x4f, 0xf0, 0x63, 0x5a, 0x07, 0xa1, 0x71, 0xdb, 0x04, 0x9e, 0x3d, 0x53,
+  0xa8, 0x75, 0x8f, 0xf5, 0x4e, 0x11, 0x56, 0x51, 0xfe, 0x13, 0x9b, 0xe7,
+  0xea, 0x65, 0x44, 0xc7, 0xc9, 0x1f, 0x66, 0xc0, 0x3d, 0x0b, 0x95, 0x7c,
+  0x4e, 0x74, 0x2f, 0xfb, 0xb2, 0x77, 0x7f, 0xb5, 0x94, 0xa8, 0xc1, 0x49,
+  0xd3, 0x44, 0x10, 0x5e, 0x7b, 0xf2, 0xd9, 0x86, 0x2b, 0x69, 0x4e, 0x11,
+  0x1e, 0xd6, 0x5e, 0xfd, 0x4a, 0x12, 0x8e, 0x0f, 0xc7, 0xcb, 0x21, 0x0c,
+  0x0e, 0xc5, 0xaa, 0x9c, 0x0c, 0x8e, 0x5a, 0xf0, 0x9c, 0xc1, 0x4b, 0xd7,
+  0x81, 0x4e, 0x19, 0x9a, 0x13, 0x94, 0xa6, 0xdd, 0x1f, 0x0f, 0x43, 0xfb,
+  0xf5, 0xd0, 0xf6, 0xa6, 0x3d, 0x51, 0x72, 0x03, 0xfd, 0xe2, 0xfa, 0xdb,
+  0x6f, 0x60, 0x46, 0xda, 0x4e, 0x18, 0xbe, 0xa0, 0x0d, 0x47, 0x2c, 0xf2,
+  0x76, 0xa1, 0xe4, 0x0b, 0xa7, 0x97, 0x58, 0x41, 0x54, 0x0d, 0xbe, 0xa6,
+  0x3d, 0xbe, 0x2e, 0x62, 0xac, 0xdb, 0x37, 0x88, 0x5e, 0xe3, 0xf4, 0xa7,
+  0x30, 0xe2, 0x74, 0x66, 0xf8, 0x77, 0xda, 0x8f, 0x2a, 0xcb, 0x73, 0xaa,
+  0x3f, 0xc5, 0xf7, 0x8c, 0x68, 0xf7, 0x84, 0x0f, 0xcb, 0x21, 0x5c, 0xb0,
+  0xbc, 0x5e, 0x4f, 0x65, 0xb5, 0xe4, 0xcd, 0x10, 0x39, 0x99, 0x58, 0x6e,
+  0x2e, 0x4e, 0x35, 0x80, 0xda, 0x84, 0x28, 0xb7, 0x77, 0xb7, 0x99, 0xdf,
+  0xff, 0x7c, 0x81, 0xd4, 0xdb, 0x5e, 0xe0, 0xff, 0x3d, 0xc8, 0xb7, 0x1e,
+  0xbf, 0xf2, 0x50, 0xdc, 0x18, 0xd4, 0x37, 0xe6, 0x2a, 0x16, 0x05, 0xc9,
+  0xf6, 0x25, 0x62, 0x83, 0x47, 0x1c, 0xc3, 0x56, 0xf4, 0x3d, 0x43, 0xfc,
+  0xfb, 0x62, 0x59, 0x9b, 0xdd, 0x62, 0xbf, 0x15, 0x45, 0x25, 0x72, 0xf8,
+  0xb4, 0x70, 0xe6, 0x3e, 0x78, 0xdc, 0x35, 0x2c, 0xd4, 0xb7, 0xee, 0x9e,
+  0xde, 0x52, 0x98, 0x38, 0xc3, 0xce, 0x55, 0x2b, 0xef, 0xe3, 0x81, 0x05,
+  0x8e, 0xdc, 0x7a, 0x79, 0xc0, 0x03, 0xb2, 0x9f, 0x36, 0x3e, 0xbb, 0xc1,
+  0xe3, 0xce, 0xc9, 0x1d, 0x05, 0x72, 0xed, 0x76, 0x8a, 0xdd, 0xcb, 0x2c,
+  0xbf, 0xeb, 0xec, 0xda, 0x63, 0xb9, 0x7f, 0xd3, 0xda, 0xbc, 0x6e, 0xed,
+  0xfc, 0x0e, 0xc2, 0x03, 0x70, 0x73, 0xfa, 0x79, 0x7b, 0x73, 0xe9, 0xc0,
+  0xd5, 0xaf, 0x98, 0x78, 0xd9, 0xbe, 0x0e, 0x85, 0x01, 0x03, 0xc9, 0xaf,
+  0x7f, 0x30, 0x9a, 0x3b, 0x82, 0xb9, 0xf9, 0xa6, 0x46, 0x18, 0x99, 0x28,
+  0x96, 0xb2, 0x3f, 0x38, 0x19, 0xb3, 0x89, 0x67, 0x54, 0xbf, 0xf3, 0x77,
+  0x5e, 0xf3, 0x3c, 0x90, 0xe3, 0xb8, 0xe6, 0x8c, 0xef, 0xc0, 0xc4, 0x96,
+  0x05, 0xf7, 0xb9, 0x76, 0xf6, 0x8e, 0x9a, 0xb2, 0xbf, 0x60, 0x1f, 0x47,
+  0x17, 0xfe, 0xc5, 0x2c, 0xf4, 0xee, 0x38, 0x02, 0x22, 0x1b, 0xe0, 0x22,
+  0x3f, 0x68, 0xbc, 0x09, 0x30, 0x1d, 0xfb, 0x17, 0xdd, 0xe9, 0x98, 0xff,
+  0x5d, 0x0d, 0x1f, 0xf8, 0x3f, 0xfb, 0xfe, 0x07, 0xe7, 0x94, 0xcf, 0xc5,
+  0x04, 0x1c, 0x00, 0x00
 };
-unsigned int enduser_setup_html_default_len = 2590;
+unsigned int enduser_setup_html_default_len = 2644;

+ 0 - 322
app/modules/enduser_setup/enduser_setup_apple.html

@@ -1,322 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-	<meta name='viewport' content='width=device-width, initial-scale=1.0'>
-	<title>WiFi Login</title>
-	<style type=text/css>
-		* {
-			margin: 0;
-			padding: 0;
-		}
-		
-		html,
-		body {
-			height: 100%;
-			font-family: sans-serif;
-			text-align: center;
-			background: #444d44;
-		}
-		
-		#content {
-			position: absolute;
-			top: 0;
-			right: 0;
-			bottom: 0;
-			left: 0;
-			width: 320px;
-			height: 480px;
-			margin: auto;
-		}
-		
-		input,
-		button,
-		select {
-			-webkit-appearance: none;
-			border-radius: 0;
-		}
-		
-		fieldset {
-			border: 0;
-			box-shadow: 0 0 15px 1px rgba(0, 0, 0, .4);
-			box-sizing: border-box;
-			padding: 20px 30px;
-			background: #fff;
-			min-height: 320px;
-			margin: -1px;
-		}
-		
-		input {
-			border: 1px solid #ccc;
-			margin-bottom: 10px;
-			width: 100%;
-			box-sizing: border-box;
-			color: #222;
-			font: 16px monospace;
-			padding: 15px;
-		}
-		
-		select {
-			font: 16px monospace;
-			background-color: transparent;
-			padding: 15px;
-		}
-		
-		button {
-			color: #fff;
-			border: 0;
-			border-radius: 3px;
-			cursor: pointer;
-			display: block;
-			font: 16px sans-serif;
-			text-decoration: none;
-			padding: 10px 5px;
-			background: #31b457;
-			width: 100%;
-		}
-		
-		button:focus,
-		button:hover {
-			box-shadow: 0 0 0 2px #fff, 0 0 0 3px #31b457;
-		}
-		
-		h3 {
-			font-size: 16px;
-			color: #666;
-			margin-bottom: 20px;
-		}
-		
-		h4 {
-			color: #ccc;
-			padding: 10px;
-		}
-		
-		.utility {
-			float: right;
-			clear: both;
-			max-width: 75%;
-			font-size: 13px;
-			color: #222;
-			margin: 10px 0;
-			padding: 5px 10px;
-			background: #ccc;
-		}
-		
-		.utility:focus,
-		.utility:hover {
-			box-shadow: 0 0 0 2px #fff, 0 0 0 3px #ccc;
-		}
-		
-		#dropdown,
-		#f2,
-		#f3,
-		#bk2 {
-			display: none;
-		}
-		
-		#dropdown {
-			position: relative;
-			width: 100%;
-			overflow: auto;
-			height: 51px;
-			margin-bottom: 10px;
-		}
-		
-		#aplist {
-			position: absolute;
-			width: 100%;
-			height: 100%;
-			top: 0;
-			left: 0;
-			bottom: 0;
-			border: 1px solid #ccc;
-			font-family: monospace;
-			padding: 10px 5px;
-		}
-		
-		#arrow {
-			color: #888;
-			position: absolute;
-			right: 8px;
-			top: 15px;
-		}
-		
-		#i {
-			text-align: center;
-		}
-	</style>
-</head>
-
-<body>
-	<div id=content>
-		<fieldset>
-			<div id=deviceId></div>
-			<div id=f1>
-				<h3>Connect device to your Wi-Fi</h3>
-				<button id=networks type=button class=utility></button>
-				<div id=dropdown>
-					<span id=arrow>&#x25bc;</span>
-					<select id=aplist name=aplist></select>
-				</div>
-				<input id=ssid type=text autocorrect=off autocapitalize=none placeholder='Wi-Fi Name' />
-				<input id=wifi_password type=text autocorrect=off autocapitalize=none autocomplete=off placeholder=Password />
-				<button id=submit type=button>Save</button>
-			</div>
-			<div id=f2>
-				<h1>Success!</h1>
-				<div id=i>
-					<h3>Your device has successfully connected to the Wi-Fi network.<br /><br/>You may now close this web page.</h3>
-				</div>
-			</div>
-			<div id=f3>
-				<h2>Trying...</h2>
-				<button id=bk2 type=button class='utility'>Go Back to Wi-Fi Setup</button>
-			</div>
-		</fieldset>
-		<h4 id='st'>Updating Status...</h4>
-	</div>
-	<script>
-		var $ = function (selector) { return document.querySelector(selector); };
-		var ab = $('#networks'), ap = $('#aplist');
-		var stopAll = false, ra, rs, submitted = false;
-
-		function show(f, y) {
-			if (y == null) y = f;
-			$(f).style.display = y == f ? 'block' : 'none';
-		}
-		function hide(f) {
-			$(f).style.display = 'none';
-		}
-		function to(cb, x) {
-			return setTimeout(cb, 1000 * x);
-		}
-		function refr() {
-			if (!stopAll)
-				fetch('/status.json?n=' + Math.random(), 'GET', newSt, 2);
-		}
-		function cur(f) {
-			show('#f1', f);
-			show('#f2', f);
-			show('#f3', f);
-		}
-		function newSt(s, d) {
-			clearTimeout(rs);
-			rs = to(refr, 3);
-
-			if (s != 200) {
-				$('#st').innerText = 'Awaiting Status (' + s + ')';
-			} else {
-				if (typeof d === 'string') {
-					d = JSON.parse(d);
-				}
-
-				$('#deviceId').innerText = "Device: " + d.deviceid;
-
-				var c = d.pairing;
-
-				var st = [
-					'Idle',
-					'Connecting...',
-					'Failed - wrong password',
-					'Failed - network not found',
-					'Failed',
-					'Wi-Fi successfully connected!'
-				][d.status];
-
-				if (st == null)
-					st = "";
-
-				if (!submitted && d.status > 1 && d.status < 5)
-					st = "Need a valid Network and Password";
-
-				$('#st').innerText = st;
-
-				if (d.status === 5) {
-					cur('#f2');
-					stopAll = true;
-					clearTimeout(ra);
-				} else if (d.status > 1) {
-					cur('#f1');
-				}
-			}
-		}
-		function submit() {
-			submitted = true;
-			var url = '/update?wifi_ssid=' + encodeURIComponent($('#ssid').value) + '&wifi_password=' + encodeURIComponent($('#wifi_password').value);
-			clearTimeout(rs);
-			fetch(url, 'GET', refr, 2);
-			cur('#f3');
-		}
-		function fetch(url, method, callback, time_out) {
-			var xhr = new XMLHttpRequest();
-			xhr.onloadend = function () {
-				callback(xhr.status, xhr.responseText);
-			}
-			xhr.ontimeout = function () {
-				callback(-1, null);
-			}
-			xhr.open(method, url, true);
-			xhr.setRequestHeader('Accept', 'application/json');
-			xhr.timeout = (time_out || 10) * 1000;
-			xhr.send();
-		}
-		function gotAp(s, json) {
-			var list;
-			if (s === 200 && json != null) {
-				if (typeof json === 'string' && json.length > 0) {
-					list = JSON.parse(json);
-				} else if (typeof json === 'object') {
-					list = json;
-				}
-
-				list.sort(function (a, b) {
-					return b.rssi - a.rssi;
-				});
-				var ops = '<option>Select a Network...</option>';
-				for (var i = 0; i < list.length; ++i) {
-					ops += '<option>' + list[i].ssid + '</option>';
-				}
-				ap.innerHTML = ops;
-				ab.disabled = false;
-				togAp(null, true);
-				ab.onclick = togAp;
-			} else {
-				ab.innerText = 'No networks found (' + s + ')';
-				ra = to(refrAp, 5);
-			}
-		}
-		function togAp(ev, force) {
-			if (!force || ap.style.display == 'block') {
-				hide('#dropdown');
-				show('#ssid');
-				ab.innerText = 'Scan for Networks';
-				ab.onclick = refrAp;
-			} else {
-				show('#dropdown');
-				hide('#ssid');
-				ab.innerText = 'Manual Entry';
-			}
-		}
-		function refrAp() {
-			ab.innerText = 'Searching for networks...';
-			ab.disabled = true;
-			ap.innerHTML = '<option disabled>Scanning...</option>';
-			if (!stopAll)
-				fetch('/aplist?n=' + Math.random(), 'GET', gotAp, 10);
-		}
-		window.onload = function() {
-		  ab.innerText = 'Scan for Networks';
-		  ab.onclick = refrAp;
-		  $('#aplist').onchange = function () {
-			  $('#ssid').value = $('#aplist').value;
-		  };
-		  $('#submit').onclick = submit;
-		  $('#bk2').onclick = function () {
-			  cur('#f1')
-		  }
-		  rs = to(refr, 0.5);
-		}
-  </script>
-</body>
-
-</html>

+ 0 - 7
docs/modules/enduser-setup.md

@@ -6,13 +6,6 @@
 This module provides a simple way of configuring ESP8266 chips without using a
 serial interface or pre-programming WiFi credentials onto the chip.
 
-!!! attention "ATTENTION Apple users"
-
-	Due to bug [#2931](https://github.com/nodemcu/nodemcu-firmware/issues/2931) the configuration does currently not work for many Safari browsers (iOS & macOS).
-	As a **workaround** there is alternative HTML file which uses another method to transfer the login credentials. It does not support sending arbitrary additional configuration parameters and likewise no `eus_params.lua` will be written. The WiFi credentials will be stored in the ESP flash.
-
-	Just copy [enduser_setup_apple.html](../../app/modules/enduser_setup/enduser_setup_apple.html) to the ESP file system and rename it to `enduser_setup.html`.
-
 After running [`enduser_setup.start()`](#enduser_setupstart), a wireless 
 network named "SetupGadget_XXXXXX" will starting. This prefix can be overridden
 in `user_config.h` by defining `ENDUSER_SETUP_AP_SSID`. Connect to that SSID