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

This commit is contained in:
Philip Gladstone 2020-09-15 08:06:38 -04:00 committed by GitHub
parent c000a0894a
commit 139af0cdd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 406 additions and 574 deletions

View File

@ -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_gz_filename[] = "enduser_setup.html.gz";
static const char http_html_filename[] = "enduser_setup.html"; 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_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[] = "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_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_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_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_header_content_len_fmt[] = "Content-length:%5d\r\n\r\n";
static const char http_html_gzip_contentencoding[] = "Content-Encoding: gzip\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[] = ... */ /* Externally defined: static const char enduser_setup_html_default[] = ... */
#include "enduser_setup/enduser_setup.html.gz.def.h" #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 typedef struct scan_listener
{ {
struct_type_t struct_type;
struct tcp_pcb *conn; struct tcp_pcb *conn;
struct scan_listener *next; struct scan_listener *next;
} scan_listener_t; } scan_listener_t;
typedef struct {
struct_type_t struct_type;
size_t length;
char data[0];
} http_request_buffer_t;
typedef struct typedef struct
{ {
struct espconn *espconn_dns_udp; struct espconn *espconn_dns_udp;
@ -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 if (strncmp(data + 5, "/setwifi ", 9) == 0) // User clicked the submit button
{ {
char* body=strstr(data, "\r\n\r\n"); char* body=strstr(data, "\r\n\r\n");
char *content_length_str = strstr(data, "Content-Length: "); if( body == NULL)
if( body == NULL || content_length_str == NULL)
{ {
enduser_setup_http_serve_header(http_client, http_header_400, LITLEN(http_header_400)); enduser_setup_http_serve_header(http_client, http_header_400, LITLEN(http_header_400));
return; return;
} }
int bodylength = atoi(content_length_str + 16);
body += 4; // length of the double CRLF found above body += 4; // length of the double CRLF found above
int bodylength = (data + data_len) - body;
switch (enduser_setup_http_handle_credentials(body, bodylength)) switch (enduser_setup_http_handle_credentials(body, bodylength))
{ {
case 0: { 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); ENDUSER_SETUP_ERROR_VOID("http_recvcb failed. Failed to handle wifi credentials.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
break; 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; return ERR_ABRT;
} }
tcp_arg_t *tcp_arg_ptr = arg;
if (!p) /* remote side closed, close our end too */ if (!p) /* remote side closed, close our end too */
{ {
ENDUSER_SETUP_DEBUG("connection closed"); ENDUSER_SETUP_DEBUG("connection closed");
scan_listener_t *l = arg; /* if it's waiting for scan, we have a ptr here */ if (tcp_arg_ptr) {
if (l) if (tcp_arg_ptr->struct_type == SCAN_LISTENER_STRUCT_TYPE) {
remove_scan_listener (l); 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); deferred_close (http_client);
return ERR_OK; return ERR_OK;
} }
char *data = calloc (1, p->tot_len + 1); http_request_buffer_t *hrb;
if (!data) if (!tcp_arg_ptr) {
return ERR_MEM; 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); tcp_recved (http_client, p->tot_len);
pbuf_free (p); 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; 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 #if ENDUSER_SETUP_DEBUG_SHOW_HTTP_REQUEST
ENDUSER_SETUP_DEBUG(data); ENDUSER_SETUP_DEBUG(data);
#endif #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) 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 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 */ /* Don't do an AP Scan while station is trying to connect to Wi-Fi */
if (state->connecting == 0) if (state->connecting == 0)
{ {
scan_listener_t *l = malloc (sizeof (scan_listener_t)); scan_listener_t *sl = malloc (sizeof (scan_listener_t));
if (!l) if (!sl)
{ {
ENDUSER_SETUP_ERROR("out of memory", ENDUSER_SETUP_ERR_OUT_OF_MEMORY, ENDUSER_SETUP_ERR_NONFATAL); 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); 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 */ /* TODO: check if also need a tcp_err() cb, or if recv() is enough */
l->conn = http_client; sl->conn = http_client;
l->next = state->scan_listeners; sl->next = state->scan_listeners;
state->scan_listeners = l; state->scan_listeners = sl;
if (!already) if (!already)
{ {
if (!wifi_station_scan(NULL, on_scan_done)) if (!wifi_station_scan(NULL, on_scan_done))
{ {
enduser_setup_http_serve_header(http_client, http_header_500, LITLEN(http_header_500)); enduser_setup_http_serve_header(http_client, http_header_500, LITLEN(http_header_500));
deferred_close (l->conn); deferred_close (sl->conn);
l->conn = 0; sl->conn = 0;
free_scan_listeners(); 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) 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) else if (strncmp(data + 4, "/status", 7) == 0)
{ {
enduser_setup_serve_status(http_client); enduser_setup_serve_status(http_client);
} }
else if (strncmp(data + 4, "/update?", 8) == 0) else if (strncmp(data + 4, "/update?", 8) == 0)
{ {
switch (enduser_setup_http_handle_credentials(data, data_len)) 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); deferred_close (http_client);
free_out: free_out:
free (data); free (hrb);
return ret; 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_accepted (state->http_pcb);
tcp_arg(pcb, 0); // Initialize to known value
tcp_recv (pcb, enduser_setup_http_recvcb); tcp_recv (pcb, enduser_setup_http_recvcb);
tcp_nagle_disable (pcb); tcp_nagle_disable (pcb);
return ERR_OK; return ERR_OK;

View File

@ -274,8 +274,13 @@
return b.rssi - a.rssi; return b.rssi - a.rssi;
}); });
var ops = '<option>Select a Network...</option>'; var ops = '<option>Select a Network...</option>';
var seen = {};
for (var i = 0; i < list.length; ++i) { 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; ap.innerHTML = ops;
ab.disabled = false; ab.disabled = false;

View File

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

View File

@ -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>

View File

@ -6,13 +6,6 @@
This module provides a simple way of configuring ESP8266 chips without using a This module provides a simple way of configuring ESP8266 chips without using a
serial interface or pre-programming WiFi credentials onto the chip. 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 After running [`enduser_setup.start()`](#enduser_setupstart), a wireless
network named "SetupGadget_XXXXXX" will starting. This prefix can be overridden 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 in `user_config.h` by defining `ENDUSER_SETUP_AP_SSID`. Connect to that SSID