commit 65cb6080de515f7f014cc0aea025a275268d8332 Author: kenji Date: Wed May 28 18:16:00 2025 -0400 Initial commit of base code diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b51b6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build/**/* +!/build/**/*.uf2 +/external/**/* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6a62249 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,53 @@ +cmake_minimum_required(VERSION 3.13) +set(PROJECT webkeyboard) +set(PICO_SDK_PATH /home/kenji/programming/pico/c/pico-sdk) +set(PICO_BOARD pico_w) +include (${PICO_SDK_PATH}/external/pico_sdk_import.cmake) +project(${PROJECT} C CXX ASM) + +set(MAKE_FS_DATA_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/external/makefsdata) +set(HTML_DIR ${CMAKE_CURRENT_LIST_DIR}/html) + +if (NOT EXISTS ${MAKE_FS_DATA_SCRIPT}) + file(DOWNLOAD + https://raw.githubusercontent.com/lwip-tcpip/lwip/e799c266facc3c70190676eccad49d6c2db2caac/src/apps/http/makefsdata/makefsdata + ${MAKE_FS_DATA_SCRIPT} + ) +endif() +message("Running makefsdata script") +execute_process(COMMAND + perl ${MAKE_FS_DATA_SCRIPT} + WORKING_DIRECTORY ${HTML_DIR} + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + ) +file(RENAME ${HTML_DIR}/fsdata.c ${CMAKE_CURRENT_LIST_DIR}/my_fsdata.c) + +pico_sdk_init() + +add_executable(${PROJECT}) +target_sources(${PROJECT} PRIVATE + main.c + server.c + hid.c + usb_descriptors.c + parse_keys.c + dhcpserver.c +) + +pico_enable_stdio_usb(${PROJECT} 1) +pico_enable_stdio_uart(${PROJECT} 1) + +pico_add_extra_outputs(${PROJECT}) + +target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) + +target_link_libraries(${PROJECT} + pico_cyw43_arch_lwip_threadsafe_background + pico_lwip_http + pico_stdlib + pico_multicore + tinyusb_device +) + + diff --git a/build/webkeyboard.uf2 b/build/webkeyboard.uf2 new file mode 100644 index 0000000..d6cde63 Binary files /dev/null and b/build/webkeyboard.uf2 differ diff --git a/dhcpserver.c b/dhcpserver.c new file mode 100644 index 0000000..ba24b63 --- /dev/null +++ b/dhcpserver.c @@ -0,0 +1,300 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// For DHCP specs see: +// https://www.ietf.org/rfc/rfc2131.txt +// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions + +#include +#include +#include + +#include "cyw43_config.h" +#include "dhcpserver.h" +#include "lwip/udp.h" + +#define DHCPDISCOVER (1) +#define DHCPOFFER (2) +#define DHCPREQUEST (3) +#define DHCPDECLINE (4) +#define DHCPACK (5) +#define DHCPNACK (6) +#define DHCPRELEASE (7) +#define DHCPINFORM (8) + +#define DHCP_OPT_PAD (0) +#define DHCP_OPT_SUBNET_MASK (1) +#define DHCP_OPT_ROUTER (3) +#define DHCP_OPT_DNS (6) +#define DHCP_OPT_HOST_NAME (12) +#define DHCP_OPT_REQUESTED_IP (50) +#define DHCP_OPT_IP_LEASE_TIME (51) +#define DHCP_OPT_MSG_TYPE (53) +#define DHCP_OPT_SERVER_ID (54) +#define DHCP_OPT_PARAM_REQUEST_LIST (55) +#define DHCP_OPT_MAX_MSG_SIZE (57) +#define DHCP_OPT_VENDOR_CLASS_ID (60) +#define DHCP_OPT_CLIENT_ID (61) +#define DHCP_OPT_END (255) + +#define PORT_DHCP_SERVER (67) +#define PORT_DHCP_CLIENT (68) + +#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8) +#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds + +#define MAC_LEN (6) +#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) + +typedef struct { + uint8_t op; // message opcode + uint8_t htype; // hardware address type + uint8_t hlen; // hardware address length + uint8_t hops; + uint32_t xid; // transaction id, chosen by client + uint16_t secs; // client seconds elapsed + uint16_t flags; + uint8_t ciaddr[4]; // client IP address + uint8_t yiaddr[4]; // your IP address + uint8_t siaddr[4]; // next server IP address + uint8_t giaddr[4]; // relay agent IP address + uint8_t chaddr[16]; // client hardware address + uint8_t sname[64]; // server host name + uint8_t file[128]; // boot file name + uint8_t options[312]; // optional parameters, variable, starts with magic +} dhcp_msg_t; + +static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) { + // family is AF_INET + // type is SOCK_DGRAM + + *udp = udp_new(); + if (*udp == NULL) { + return -ENOMEM; + } + + // Register callback + udp_recv(*udp, cb_udp_recv, (void *)cb_data); + + return 0; // success +} + +static void dhcp_socket_free(struct udp_pcb **udp) { + if (*udp != NULL) { + udp_remove(*udp); + *udp = NULL; + } +} + +static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) { + ip_addr_t addr; + IP4_ADDR(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + // TODO convert lwIP errors to errno + return udp_bind(*udp, &addr, port); +} + +static int dhcp_socket_sendto(struct udp_pcb **udp, const void *buf, size_t len, uint32_t ip, uint16_t port) { + if (len > 0xffff) { + len = 0xffff; + } + + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (p == NULL) { + return -ENOMEM; + } + + memcpy(p->payload, buf, len); + + ip_addr_t dest; + IP4_ADDR(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + err_t err = udp_sendto(*udp, p, &dest, port); + + pbuf_free(p); + + if (err != ERR_OK) { + return err; + } + + return len; +} + +static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) { + for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) { + if (opt[i] == cmd) { + return &opt[i]; + } + i += 2 + opt[i + 1]; + } + return NULL; +} + +static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, void *data) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = n; + memcpy(o, data, n); + *opt = o + n; +} + +static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = 1; + *o++ = val; + *opt = o; +} + +static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = 4; + *o++ = val >> 24; + *o++ = val >> 16; + *o++ = val >> 8; + *o++ = val; + *opt = o; +} + +static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) { + dhcp_server_t *d = arg; + (void)upcb; + (void)src_addr; + (void)src_port; + + // This is around 548 bytes + dhcp_msg_t dhcp_msg; + + #define DHCP_MIN_SIZE (240 + 3) + if (p->tot_len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0); + if (len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + dhcp_msg.op = DHCPOFFER; + memcpy(&dhcp_msg.yiaddr, &d->ip.addr, 4); + + uint8_t *opt = (uint8_t *)&dhcp_msg.options; + opt += 4; // assume magic cookie: 99, 130, 83, 99 + + switch (opt[2]) { + case DHCPDISCOVER: { + int yi = DHCPS_MAX_IP; + for (int i = 0; i < DHCPS_MAX_IP; ++i) { + if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, use this IP address + yi = i; + break; + } + if (yi == DHCPS_MAX_IP) { + // Look for a free IP address + if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP available + yi = i; + } + uint32_t expiry = d->lease[i].expiry << 16 | 0xffff; + if ((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) { + // IP expired, reuse it + memset(d->lease[i].mac, 0, MAC_LEN); + yi = i; + } + } + } + if (yi == DHCPS_MAX_IP) { + // No more IP addresses left + goto ignore_request; + } + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER); + break; + } + + case DHCPREQUEST: { + uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP); + if (o == NULL) { + // Should be NACK + goto ignore_request; + } + if (memcmp(o + 2, &d->ip.addr, 3) != 0) { + // Should be NACK + goto ignore_request; + } + uint8_t yi = o[5] - DHCPS_BASE_IP; + if (yi >= DHCPS_MAX_IP) { + // Should be NACK + goto ignore_request; + } + if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, ok to use this IP address + } else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP unused, ok to use this IP address + memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN); + } else { + // IP already in use + // Should be NACK + goto ignore_request; + } + d->lease[yi].expiry = (cyw43_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16; + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK); + // printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n", + // dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5], + // dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]); + break; + } + + default: + goto ignore_request; + } + + opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &d->ip.addr); + opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &d->nm.addr); + opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &d->ip.addr); // aka gateway; can have mulitple addresses + opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have mulitple addresses + opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S); + *opt++ = DHCP_OPT_END; + dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT); + +ignore_request: + pbuf_free(p); +} + +void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) { + ip_addr_copy(d->ip, *ip); + ip_addr_copy(d->nm, *nm); + memset(d->lease, 0, sizeof(d->lease)); + if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) { + return; + } + dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER); +} + +void dhcp_server_deinit(dhcp_server_t *d) { + dhcp_socket_free(&d->udp); +} diff --git a/dhcpserver.h b/dhcpserver.h new file mode 100644 index 0000000..2349d2e --- /dev/null +++ b/dhcpserver.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H +#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H + +#include "lwip/ip_addr.h" + +#define DHCPS_BASE_IP (16) +#define DHCPS_MAX_IP (8) + +typedef struct _dhcp_server_lease_t { + uint8_t mac[6]; + uint16_t expiry; +} dhcp_server_lease_t; + +typedef struct _dhcp_server_t { + ip_addr_t ip; + ip_addr_t nm; + dhcp_server_lease_t lease[DHCPS_MAX_IP]; + struct udp_pcb *udp; +} dhcp_server_t; + +void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm); +void dhcp_server_deinit(dhcp_server_t *d); + +#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H diff --git a/hid.c b/hid.c new file mode 100644 index 0000000..15c263b --- /dev/null +++ b/hid.c @@ -0,0 +1,136 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * sekigon-gonnoc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include +#include + +#include "pico/stdlib.h" + +#include "tusb.h" + +#include "usb_descriptors.h" +#include "server.h" +#include "main.h" + + +/*------------- MAIN -------------*/ +int run_hid_device(void) { + // init device stack on native usb (roothub port0) + tud_init(0); + + while (true) { + tud_task(); // tinyusb device task + //tud_cdc_write_flush(); + } + + return 0; +} + + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) + +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + + + if (instance == 0 && report_type==HID_REPORT_TYPE_OUTPUT && report_id==REPORT_ID_KEYBOARD && bufsize==1) { + //received keyboard LED status, so update + set_indicator(buffer); + } + + char tempbuf[128]; + size_t count; + if(bufsize>0) { + count = sprintf(tempbuf, "\nReceived device set report type %u on interface %u with ID %u (%u)\n", report_type, instance, report_id, bufsize); + tud_cdc_write(tempbuf, count); + for(int i=0;i0) { + count = sprintf(tempbuf, "\nReceived device get report type %u on interface %u with ID %u (%u)\n", report_type, instance, report_id, reqlen); + tud_cdc_write(tempbuf, count); + for(int i=0;i0) { + count = sprintf(tempbuf, "\nDevice sent report on interface %u (%u)\n", instance, len); + tud_cdc_write(tempbuf, count); + for(int i=0;i + + + + +Web Keyboard + + + + + + + + +
+
+
+
+ +
+ +
+
Currently pressed keys:
+
+
+ +
+ + +
+ +
+ +
+ + + + diff --git a/html/indicators.shtml b/html/indicators.shtml new file mode 100644 index 0000000..1e9705b --- /dev/null +++ b/html/indicators.shtml @@ -0,0 +1,15 @@ + + + + + +Keyboard Indicators + + + +
NumLock
+
CapsLock
+
ScrollLock
+ + + diff --git a/html/success.html b/html/success.html new file mode 100644 index 0000000..ea0cf74 --- /dev/null +++ b/html/success.html @@ -0,0 +1,35 @@ + + + + + +Success + + + + + + + + +

Success

+ +

Redirecting in 15...

+ + + + diff --git a/html/wifi.shtml b/html/wifi.shtml new file mode 100644 index 0000000..1a9ca0e --- /dev/null +++ b/html/wifi.shtml @@ -0,0 +1,137 @@ + + + + + +Web Keyboard Wi-Fi Settings + + + + + + + + + +

Web Keyboard Wi-Fi Settings

+ +
+
+

Wi-Fi Network

+ +
+
SSID:
+
>
+
+ +
+
Password:
+
>
+
+ +
+
Hostname:
+
>
+
+ +

Manual Network Configuration

+ +
+
Use DHCP:
+
> +
+
+ +
+
IP Address:
+
>. + >. + >. + > +
+
+ +
+
Netmask:
+
>. + >. + >. + > +
+
+ +
+
Default Gateway:
+
>. + >. + >. + > +
+
+ +
+
+
*
+ *Device will need to be rebooted for settings to take effect.
+
+ +
+ + + + diff --git a/lwipopts.h b/lwipopts.h new file mode 100644 index 0000000..60c177f --- /dev/null +++ b/lwipopts.h @@ -0,0 +1,100 @@ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +// Common settings used in most of the pico_w examples +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) + +// allow override in some examples +#ifndef NO_SYS +#define NO_SYS 1 +#endif +// allow override in some examples +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif +#if PICO_CYW43_ARCH_POLL +#define MEM_LIBC_MALLOC 1 +#else +// MEM_LIBC_MALLOC is incompatible with non polling versions +#define MEM_LIBC_MALLOC 0 +#endif +#define MEM_ALIGNMENT 4 +#ifndef MEM_SIZE +#define MEM_SIZE 4000 +#endif +#define MEMP_NUM_TCP_SEG 32 +#define MEMP_NUM_ARP_QUEUE 10 +#define PBUF_POOL_SIZE 24 +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_ICMP 1 +#define LWIP_RAW 1 +#define TCP_WND (8 * TCP_MSS) +#define TCP_MSS 1460 +#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETCONN 0 +#define MEM_STATS 0 +#define SYS_STATS 0 +#define MEMP_STATS 0 +#define LINK_STATS 0 +// #define ETH_PAD_SIZE 2 +#define LWIP_CHKSUM_ALGORITHM 3 +#define LWIP_DHCP 1 +#define LWIP_IPV4 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DNS 1 +#define LWIP_TCP_KEEPALIVE 1 +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +#ifndef NDEBUG +#define LWIP_DEBUG 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 1 +#endif + +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define PPP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF + + +// HTTPD stuff +#define LWIP_HTTPD 1 +#define LWIP_HTTPD_CGI 1 +#define LWIP_HTTPD_SSI 1 +#define LWIP_HTTPD_SSI_INCLUDE_TAG 0 +#define HTTPD_FSDATA_FILE "my_fsdata.c" + + +#endif /* __LWIPOPTS_H__ */ diff --git a/main.c b/main.c new file mode 100644 index 0000000..17016c7 --- /dev/null +++ b/main.c @@ -0,0 +1,26 @@ +#include + +#include "pico/stdlib.h" +#include "pico/multicore.h" + +#include "main.h" +#include "server.h" +#include "hid.h" + +int main() { + stdio_init_all(); + + multicore_reset_core1(); + multicore_launch_core1(core1_main); + + multicore_lockout_victim_init(); + + run_hid_device(); +} + + +void core1_main() { + run_http_server(); +} + + diff --git a/main.h b/main.h new file mode 100644 index 0000000..44821c6 --- /dev/null +++ b/main.h @@ -0,0 +1,7 @@ +#ifndef MAIN_H_ +#define MAIN_H_ + +int main(); +void core1_main(); + +#endif diff --git a/my_fsdata.c b/my_fsdata.c new file mode 100644 index 0000000..d2e55f8 --- /dev/null +++ b/my_fsdata.c @@ -0,0 +1,1388 @@ +static const unsigned char data_fsdata_c[] = { + /* /fsdata.c */ + 0x2f, 0x66, 0x73, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x63, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0xd, 0xa, 0xd, 0xa, +}; + +static const unsigned char data_indicators_shtml[] = { + /* /indicators.shtml */ + 0x2f, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0x3c, + 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x68, + 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, + 0xa, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x4b, 0x65, + 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x3c, 0x2f, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x65, + 0x61, 0x64, 0x3e, 0xa, 0xa, 0x3c, 0x62, 0x6f, 0x64, 0x79, + 0x3e, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, + 0x22, 0x6e, 0x75, 0x6d, 0x22, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x3d, 0x22, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x6e, 0x75, + 0x6d, 0x2d, 0x2d, 0x3e, 0x22, 0x3e, 0x4e, 0x75, 0x6d, 0x4c, + 0x6f, 0x63, 0x6b, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x63, + 0x61, 0x70, 0x73, 0x22, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x3d, 0x22, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x63, 0x61, 0x70, + 0x73, 0x2d, 0x2d, 0x3e, 0x22, 0x3e, 0x43, 0x61, 0x70, 0x73, + 0x4c, 0x6f, 0x63, 0x6b, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, + 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x22, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x3c, 0x21, 0x2d, 0x2d, 0x23, + 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x2d, 0x2d, 0x3e, 0x22, + 0x3e, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x4c, 0x6f, 0x63, + 0x6b, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x3c, 0x2f, + 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x68, + 0x74, 0x6d, 0x6c, 0x3e, 0xa, }; + +static const unsigned char data_wifi_shtml[] = { + /* /wifi.shtml */ + 0x2f, 0x77, 0x69, 0x66, 0x69, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0x3c, + 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x68, + 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, + 0xa, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x57, 0x65, + 0x62, 0x20, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x20, 0x57, 0x69, 0x2d, 0x46, 0x69, 0x20, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3c, 0x2f, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x73, 0x74, 0x79, 0x6c, + 0x65, 0x3e, 0xa, 0x64, 0x69, 0x76, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x7b, 0xa, 0x9, + 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, + 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x65, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x3b, 0xa, 0x7d, 0xa, 0xa, + 0x64, 0x69, 0x76, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, + 0x3e, 0x20, 0x64, 0x69, 0x76, 0x20, 0x7b, 0xa, 0x9, 0x64, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x69, 0x6e, + 0x6c, 0x69, 0x6e, 0x65, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, 0x2e, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x20, 0x7b, 0xa, 0x9, 0x74, 0x65, + 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x3b, 0xa, 0x9, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3a, 0x20, 0x31, 0x35, 0x30, 0x70, 0x78, + 0x3b, 0xa, 0x7d, 0xa, 0x64, 0x69, 0x76, 0x2e, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x20, 0x7b, 0xa, 0x9, 0x74, 0x65, 0x78, + 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c, + 0x65, 0x66, 0x74, 0x3b, 0xa, 0x7d, 0xa, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x20, 0x7b, 0xa, 0x9, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, + 0x20, 0x33, 0x65, 0x6d, 0x3b, 0xa, 0x7d, 0xa, 0x3c, 0x2f, + 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x3e, 0xa, 0xa, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x67, + 0x67, 0x6c, 0x65, 0x44, 0x48, 0x43, 0x50, 0x28, 0x29, 0x20, + 0x7b, 0xa, 0x9, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x6f, 0x78, + 0x65, 0x73, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x27, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x27, 0x29, 0x3b, 0xa, 0x9, + 0x69, 0x66, 0x20, 0x28, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x27, 0x64, + 0x68, 0x63, 0x70, 0x27, 0x29, 0x2e, 0x63, 0x68, 0x65, 0x63, + 0x6b, 0x65, 0x64, 0x20, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x66, 0x6f, 0x72, 0x20, 0x28, 0x62, 0x6f, 0x78, 0x20, 0x6f, + 0x66, 0x20, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x29, 0x20, 0x7b, + 0xa, 0x9, 0x9, 0x9, 0x62, 0x6f, 0x78, 0x2e, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x3b, 0xa, 0x9, 0x9, 0x7d, 0xa, 0x9, + 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0xa, 0x9, + 0x9, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x62, 0x6f, 0x78, 0x20, + 0x6f, 0x66, 0x20, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x29, 0x20, + 0x7b, 0xa, 0x9, 0x9, 0x9, 0x62, 0x6f, 0x78, 0x2e, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x3d, 0x20, + 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0xa, 0x9, 0x9, 0x7d, + 0xa, 0x9, 0x7d, 0xa, 0x7d, 0xa, 0xa, 0x77, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x2e, 0x6f, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x20, 0x3d, 0x20, 0x28, 0x29, 0x20, 0x3d, 0x3e, 0x20, 0x7b, + 0xa, 0x9, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x44, 0x48, + 0x43, 0x50, 0x28, 0x29, 0x3b, 0xa, 0x9, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, + 0x28, 0x27, 0x64, 0x68, 0x63, 0x70, 0x27, 0x29, 0x2e, 0x6f, + 0x6e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x3d, 0x20, + 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x44, 0x48, 0x43, 0x50, + 0x3b, 0xa, 0x7d, 0x3b, 0xa, 0xa, 0x3c, 0x2f, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0xa, 0xa, 0x3c, 0x62, 0x6f, 0x64, + 0x79, 0x3e, 0xa, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x3e, 0x3c, + 0x68, 0x31, 0x3e, 0x57, 0x65, 0x62, 0x20, 0x4b, 0x65, 0x79, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x57, 0x69, 0x2d, 0x46, + 0x69, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x22, 0x3e, 0xa, 0x3c, 0x66, 0x6f, + 0x72, 0x6d, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x3d, + 0x22, 0x67, 0x65, 0x74, 0x22, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x3d, 0x22, 0x77, 0x69, 0x66, 0x69, 0x2e, 0x63, + 0x67, 0x69, 0x22, 0x3e, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, + 0x3e, 0x3c, 0x68, 0x32, 0x3e, 0x57, 0x69, 0x2d, 0x46, 0x69, + 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x3c, 0x2f, + 0x68, 0x32, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, + 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x22, 0x3e, 0x53, 0x53, 0x49, 0x44, 0x3a, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x22, 0x3e, 0x3c, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, + 0x65, 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x73, + 0x73, 0x69, 0x64, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, + 0x22, 0x73, 0x73, 0x69, 0x64, 0x22, 0xa, 0x9, 0x9, 0x9, + 0x6d, 0x61, 0x78, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3d, + 0x22, 0x33, 0x32, 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, + 0x73, 0x73, 0x69, 0x64, 0x2d, 0x2d, 0x3e, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x64, 0x69, + 0x76, 0x3e, 0xa, 0x9, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x22, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, + 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3e, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x3c, 0x2f, 0x64, 0x69, + 0x76, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x22, 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x70, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x20, 0x69, 0x64, 0x3d, + 0x22, 0x70, 0x61, 0x73, 0x73, 0x22, 0x20, 0x6e, 0x61, 0x6d, + 0x65, 0x3d, 0x22, 0x70, 0x61, 0x73, 0x73, 0x22, 0xa, 0x9, + 0x9, 0x9, 0x6d, 0x61, 0x78, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x3d, 0x22, 0x36, 0x33, 0x22, 0x20, 0x3c, 0x21, 0x2d, + 0x2d, 0x23, 0x70, 0x61, 0x73, 0x73, 0x2d, 0x2d, 0x3e, 0x3e, + 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, 0x9, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x22, 0x3e, 0xa, 0x9, 0x9, 0x3c, + 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, + 0x22, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3e, 0x48, 0x6f, + 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x3c, 0x2f, 0x64, + 0x69, 0x76, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x22, 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, + 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x68, 0x6f, + 0x73, 0x74, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, + 0x68, 0x6f, 0x73, 0x74, 0x22, 0xa, 0x9, 0x9, 0x9, 0x6d, + 0x61, 0x78, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3d, 0x22, + 0x36, 0x33, 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x68, + 0x6f, 0x73, 0x74, 0x2d, 0x2d, 0x3e, 0x3e, 0x3c, 0x2f, 0x64, + 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x3e, 0x3c, + 0x68, 0x32, 0x3e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x20, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x3c, 0x2f, 0x68, 0x32, 0x3e, 0xa, 0xa, 0x9, 0x3c, + 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, + 0x22, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x3e, 0xa, 0x9, + 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x3d, 0x22, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3e, + 0x55, 0x73, 0x65, 0x20, 0x44, 0x48, 0x43, 0x50, 0x3a, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, + 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x3e, 0x3c, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, + 0x63, 0x68, 0x65, 0x63, 0x6b, 0x62, 0x6f, 0x78, 0x22, 0x20, + 0x69, 0x64, 0x3d, 0x22, 0x64, 0x68, 0x63, 0x70, 0x22, 0x20, + 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x64, 0x68, 0x63, 0x70, + 0x22, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x21, 0x2d, 0x2d, 0x23, + 0x64, 0x68, 0x63, 0x70, 0x2d, 0x2d, 0x3e, 0x3e, 0xa, 0x9, + 0x9, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, 0x9, 0x3c, 0x64, + 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x3e, 0xa, 0x9, 0x9, + 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x3d, 0x22, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3e, 0x49, + 0x50, 0x20, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, + 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x9, 0x3c, + 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, + 0x22, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x3e, 0x3c, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, + 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, + 0x22, 0x69, 0x70, 0x30, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, + 0x3d, 0x22, 0x69, 0x70, 0x30, 0x22, 0xa, 0x9, 0x9, 0x9, + 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x20, 0x70, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, 0x5b, 0x30, 0x2d, 0x39, + 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, 0x22, 0x20, 0x3c, 0x21, + 0x2d, 0x2d, 0x23, 0x69, 0x70, 0x30, 0x2d, 0x2d, 0x3e, 0x3e, + 0x2e, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, + 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x69, 0x70, + 0x31, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x69, + 0x70, 0x31, 0x22, 0xa, 0x9, 0x9, 0x9, 0x9, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x22, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x6e, 0x3d, 0x22, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, + 0x2c, 0x33, 0x7d, 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, + 0x69, 0x70, 0x31, 0x2d, 0x2d, 0x3e, 0x3e, 0x2e, 0xa, 0x9, + 0x9, 0x9, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, + 0x20, 0x69, 0x64, 0x3d, 0x22, 0x69, 0x70, 0x32, 0x22, 0x20, + 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x69, 0x70, 0x32, 0x22, + 0xa, 0x9, 0x9, 0x9, 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x3d, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, + 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, + 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, + 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x69, 0x70, 0x32, + 0x2d, 0x2d, 0x3e, 0x3e, 0x2e, 0xa, 0x9, 0x9, 0x9, 0x3c, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, + 0x3d, 0x22, 0x69, 0x70, 0x33, 0x22, 0x20, 0x6e, 0x61, 0x6d, + 0x65, 0x3d, 0x22, 0x69, 0x70, 0x33, 0x22, 0xa, 0x9, 0x9, + 0x9, 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x20, 0x70, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, 0x5b, 0x30, 0x2d, + 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, 0x22, 0x20, 0x3c, + 0x21, 0x2d, 0x2d, 0x23, 0x69, 0x70, 0x33, 0x2d, 0x2d, 0x3e, + 0x3e, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, + 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, + 0x3a, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x9, + 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x3d, 0x22, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x3e, 0x3c, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, + 0x3d, 0x22, 0x6d, 0x61, 0x73, 0x6b, 0x30, 0x22, 0x20, 0x6e, + 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x6d, 0x61, 0x73, 0x6b, 0x30, + 0x22, 0xa, 0x9, 0x9, 0x9, 0x9, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x3d, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x22, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x3d, + 0x22, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x33, + 0x7d, 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x6d, 0x61, + 0x73, 0x6b, 0x30, 0x2d, 0x2d, 0x3e, 0x3e, 0x2e, 0xa, 0x9, + 0x9, 0x9, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, + 0x20, 0x69, 0x64, 0x3d, 0x22, 0x6d, 0x61, 0x73, 0x6b, 0x31, + 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x6d, 0x61, + 0x73, 0x6b, 0x31, 0x22, 0xa, 0x9, 0x9, 0x9, 0x9, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x22, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, + 0x72, 0x6e, 0x3d, 0x22, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x7b, + 0x31, 0x2c, 0x33, 0x7d, 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, + 0x23, 0x6d, 0x61, 0x73, 0x6b, 0x31, 0x2d, 0x2d, 0x3e, 0x3e, + 0x2e, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, + 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x6d, 0x61, + 0x73, 0x6b, 0x32, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, + 0x22, 0x6d, 0x61, 0x73, 0x6b, 0x32, 0x22, 0xa, 0x9, 0x9, + 0x9, 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x20, 0x70, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, 0x5b, 0x30, 0x2d, + 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, 0x22, 0x20, 0x3c, + 0x21, 0x2d, 0x2d, 0x23, 0x6d, 0x61, 0x73, 0x6b, 0x32, 0x2d, + 0x2d, 0x3e, 0x3e, 0x2e, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, + 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, + 0x22, 0x6d, 0x61, 0x73, 0x6b, 0x33, 0x22, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x3d, 0x22, 0x6d, 0x61, 0x73, 0x6b, 0x33, 0x22, + 0xa, 0x9, 0x9, 0x9, 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x3d, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, + 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, + 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, + 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x6d, 0x61, 0x73, + 0x6b, 0x33, 0x2d, 0x2d, 0x3e, 0x3e, 0xa, 0x9, 0x9, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x64, + 0x69, 0x76, 0x3e, 0xa, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x22, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, + 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3e, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x20, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x3a, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x9, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, + 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, + 0x69, 0x64, 0x3d, 0x22, 0x67, 0x77, 0x30, 0x22, 0x20, 0x6e, + 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x67, 0x77, 0x30, 0x22, 0xa, + 0x9, 0x9, 0x9, 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, + 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x20, + 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, 0x5b, + 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, 0x22, + 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x67, 0x77, 0x30, 0x2d, + 0x2d, 0x3e, 0x3e, 0x2e, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, + 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, + 0x22, 0x67, 0x77, 0x31, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, + 0x3d, 0x22, 0x67, 0x77, 0x31, 0x22, 0xa, 0x9, 0x9, 0x9, + 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x20, 0x70, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, 0x5b, 0x30, 0x2d, 0x39, + 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, 0x22, 0x20, 0x3c, 0x21, + 0x2d, 0x2d, 0x23, 0x67, 0x77, 0x31, 0x2d, 0x2d, 0x3e, 0x3e, + 0x2e, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, + 0x78, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x67, 0x77, + 0x32, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x67, + 0x77, 0x32, 0x22, 0xa, 0x9, 0x9, 0x9, 0x9, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x22, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x6e, 0x3d, 0x22, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, + 0x2c, 0x33, 0x7d, 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, + 0x67, 0x77, 0x32, 0x2d, 0x2d, 0x3e, 0x3e, 0x2e, 0xa, 0x9, + 0x9, 0x9, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, + 0x20, 0x69, 0x64, 0x3d, 0x22, 0x67, 0x77, 0x33, 0x22, 0x20, + 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x67, 0x77, 0x33, 0x22, + 0xa, 0x9, 0x9, 0x9, 0x9, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x3d, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, + 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x3d, 0x22, + 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x33, 0x7d, + 0x22, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x67, 0x77, 0x33, + 0x2d, 0x2d, 0x3e, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x2f, 0x64, + 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x22, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x22, 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x22, 0x53, 0x61, 0x76, + 0x65, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x73, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x2a, 0x3c, 0x62, + 0x72, 0x3e, 0xa, 0x9, 0x9, 0x9, 0x2a, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6e, + 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, + 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x65, 0x64, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x61, 0x6b, 0x65, 0x20, + 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x2e, 0x3c, 0x2f, 0x64, + 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0x3c, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0xa, + 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, 0x3c, 0x2f, + 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x68, + 0x74, 0x6d, 0x6c, 0x3e, 0xa, }; + +static const unsigned char data_index_html[] = { + /* /index.html */ + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0x3c, + 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x68, + 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, + 0xa, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x57, 0x65, + 0x62, 0x20, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0xa, + 0x3c, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x64, + 0x69, 0x76, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x20, 0x3e, 0x20, 0x64, 0x69, 0x76, 0x20, 0x7b, + 0xa, 0x9, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, + 0x20, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x2d, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, + 0x76, 0x23, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x73, 0x20, 0x7b, 0xa, 0x9, 0x74, 0x65, 0x78, 0x74, + 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x9, 0x76, 0x65, 0x72, + 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2d, 0x61, 0x6c, 0x69, 0x67, + 0x6e, 0x3a, 0x20, 0x74, 0x6f, 0x70, 0x3b, 0xa, 0x9, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, + 0x31, 0x2e, 0x32, 0x65, 0x6d, 0x3b, 0xa, 0x7d, 0xa, 0xa, + 0x64, 0x69, 0x76, 0x23, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, + 0x74, 0x6f, 0x72, 0x73, 0x20, 0x2e, 0x6f, 0x6e, 0x20, 0x7b, + 0xa, 0x9, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, + 0x23, 0x34, 0x30, 0x66, 0x66, 0x34, 0x30, 0x3b, 0xa, 0x7d, + 0xa, 0xa, 0x64, 0x69, 0x76, 0x23, 0x69, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x2e, 0x6f, 0x66, + 0x66, 0x20, 0x7b, 0xa, 0x9, 0x62, 0x61, 0x63, 0x6b, 0x67, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3a, 0x20, 0x23, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, 0x23, 0x6b, + 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x7b, 0xa, + 0x9, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3b, 0xa, 0x7d, 0xa, + 0xa, 0x64, 0x69, 0x76, 0x2e, 0x6b, 0x65, 0x79, 0x20, 0x7b, + 0xa, 0x9, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3a, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, + 0xa, 0x9, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, + 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x74, 0x6f, + 0x70, 0x3b, 0xa, 0x9, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x3a, 0x20, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x2d, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3b, 0xa, 0x9, 0x62, 0x61, + 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x3b, 0xa, 0x9, 0x6d, 0x61, 0x72, 0x67, + 0x69, 0x6e, 0x3a, 0x20, 0x31, 0x70, 0x78, 0x3b, 0xa, 0x9, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x33, 0x65, 0x6d, + 0x3b, 0xa, 0x9, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, + 0x20, 0x33, 0x2e, 0x35, 0x65, 0x6d, 0x3b, 0xa, 0x9, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, + 0x30, 0x2e, 0x38, 0x65, 0x6d, 0x3b, 0xa, 0x7d, 0xa, 0xa, + 0x64, 0x69, 0x76, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x20, 0x7b, 0xa, 0x9, 0x62, 0x61, 0x63, 0x6b, 0x67, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x34, 0x30, 0x34, 0x30, + 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, 0x2e, 0x62, + 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x7b, 0xa, 0x9, 0x6f, 0x70, + 0x61, 0x63, 0x69, 0x74, 0x79, 0x3a, 0x20, 0x30, 0x3b, 0xa, + 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, 0x2e, 0x69, 0x6e, 0x66, + 0x6f, 0x20, 0x64, 0x69, 0x76, 0x20, 0x7b, 0xa, 0x9, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, + 0x31, 0x2e, 0x35, 0x65, 0x6d, 0x3b, 0xa, 0x9, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x69, 0x6e, 0x6c, + 0x69, 0x6e, 0x65, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3b, + 0xa, 0x9, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, + 0x31, 0x65, 0x6d, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, + 0x76, 0x23, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x20, 0x64, + 0x69, 0x76, 0x20, 0x7b, 0xa, 0x9, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x20, 0x39, 0x65, 0x6d, 0x3b, 0xa, 0x9, 0x64, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x69, 0x6e, + 0x6c, 0x69, 0x6e, 0x65, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x3b, 0xa, 0x9, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, + 0x20, 0x23, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x3b, 0xa, + 0x9, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x31, + 0x65, 0x6d, 0x3b, 0xa, 0x9, 0x74, 0x65, 0x78, 0x74, 0x2d, + 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, + 0x76, 0x23, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x20, 0x2e, + 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x64, 0x6f, 0x77, 0x6e, 0x7b, + 0xa, 0x9, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, + 0x23, 0x34, 0x30, 0x34, 0x30, 0x66, 0x66, 0x3b, 0xa, 0x7d, + 0xa, 0xa, 0x64, 0x69, 0x76, 0x23, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x20, + 0x7b, 0xa, 0x9, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x3a, 0x20, 0x68, 0x69, 0x64, 0x64, 0x65, + 0x6e, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, 0x2e, + 0x6d, 0x65, 0x6e, 0x75, 0x20, 0x7b, 0xa, 0x9, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x69, 0x6e, 0x6c, + 0x69, 0x6e, 0x65, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3b, + 0xa, 0x9, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, + 0x20, 0x31, 0x65, 0x6d, 0x3b, 0xa, 0x9, 0x62, 0x61, 0x63, + 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, + 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0x20, 0x61, 0x20, 0x7b, 0xa, + 0x9, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x6e, 0x6f, + 0x6e, 0x65, 0x3b, 0xa, 0x9, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x3a, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x3b, + 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, 0x2e, 0x6d, 0x65, + 0x6e, 0x75, 0x20, 0x61, 0x3a, 0x68, 0x6f, 0x76, 0x65, 0x72, + 0x20, 0x7b, 0xa, 0x9, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, + 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, + 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x65, + 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x3c, 0x2f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x3e, 0xa, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x65, + 0x79, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0xa, 0x76, + 0x61, 0x72, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x71, 0x75, + 0x65, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x3b, 0xa, + 0x76, 0x61, 0x72, 0x20, 0x63, 0x75, 0x72, 0x4c, 0x65, 0x64, + 0x20, 0x3d, 0x20, 0x30, 0x3b, 0xa, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x5b, + 0xa, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x6e, 0x75, + 0x6d, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x4c, 0x6f, 0x63, 0x6b, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x63, 0x61, 0x70, 0x73, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x61, 0x70, 0x73, 0x4c, + 0x6f, 0x63, 0x6b, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x4c, 0x6f, 0x63, + 0x6b, 0x22, 0x7d, 0xa, 0x5d, 0x3b, 0xa, 0x63, 0x6f, 0x6e, + 0x73, 0x74, 0x20, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x5f, 0x6c, + 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x5b, 0xa, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x22, 0x2c, 0x20, 0x6b, + 0x65, 0x79, 0x73, 0x3a, 0x20, 0x5b, 0x22, 0x57, 0x61, 0x6b, + 0x65, 0x55, 0x70, 0x22, 0x5d, 0x7d, 0x2c, 0xa, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x73, 0x65, 0x74, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x43, 0x54, 0x52, 0x4c, 0x2b, 0x41, 0x4c, 0x54, 0x2b, + 0x44, 0x45, 0x4c, 0x22, 0x2c, 0x20, 0x6b, 0x65, 0x79, 0x73, + 0x3a, 0x20, 0x5b, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x2c, 0x22, 0x41, 0x6c, + 0x74, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x2c, 0x22, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x22, 0x5d, 0x7d, 0x2c, 0xa, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x63, 0x6c, 0x6f, 0x73, + 0x65, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x41, 0x4c, 0x54, 0x2b, 0x46, 0x34, 0x22, 0x2c, + 0x20, 0x6b, 0x65, 0x79, 0x73, 0x3a, 0x20, 0x5b, 0x22, 0x41, + 0x6c, 0x74, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x2c, 0x20, 0x22, + 0x46, 0x34, 0x22, 0x5d, 0x7d, 0x2c, 0xa, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x22, + 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x41, 0x4c, 0x54, 0x2b, 0x54, 0x61, 0x62, 0x22, 0x2c, 0x20, + 0x6b, 0x65, 0x79, 0x73, 0x3a, 0x20, 0x5b, 0x22, 0x41, 0x6c, + 0x74, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x2c, 0x20, 0x22, 0x54, + 0x61, 0x62, 0x22, 0x5d, 0x7d, 0xa, 0x5d, 0x3b, 0xa, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6c, + 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x5b, 0xa, 0x9, 0x5b, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x45, + 0x73, 0x63, 0x61, 0x70, 0x65, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x53, 0x43, 0x22, + 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x32, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x46, 0x31, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x46, 0x31, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x46, 0x32, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x46, 0x32, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x46, 0x33, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x46, 0x33, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x46, 0x34, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x46, 0x34, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x46, + 0x35, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x46, 0x35, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x46, 0x36, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x46, + 0x36, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x46, 0x37, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x46, 0x37, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x46, 0x38, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x46, 0x38, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x46, 0x39, 0x22, + 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x46, 0x39, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x46, 0x31, 0x30, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x46, 0x31, + 0x30, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x46, 0x31, 0x31, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x46, 0x31, 0x31, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x46, 0x31, 0x32, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x46, 0x31, 0x32, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x53, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x50, 0x72, 0x69, 0x6e, + 0x74, 0x3c, 0x62, 0x72, 0x3e, 0x53, 0x63, 0x72, 0x65, 0x65, + 0x6e, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x4c, + 0x6f, 0x63, 0x6b, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, + 0x3c, 0x62, 0x72, 0x3e, 0x4c, 0x6f, 0x63, 0x6b, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x50, 0x61, 0x75, 0x73, 0x65, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x50, 0x61, 0x75, 0x73, + 0x65, 0x22, 0x7d, 0xa, 0x9, 0x5d, 0x2c, 0xa, 0x9, 0x5b, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x42, + 0x61, 0x63, 0x6b, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x7e, + 0x3c, 0x62, 0x72, 0x3e, 0x60, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, + 0x69, 0x74, 0x31, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x21, 0x3c, 0x62, 0x72, 0x3e, 0x31, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x74, 0x32, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x40, + 0x3c, 0x62, 0x72, 0x3e, 0x32, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, + 0x69, 0x74, 0x33, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x23, 0x3c, 0x62, 0x72, 0x3e, 0x33, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x74, 0x34, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x24, + 0x3c, 0x62, 0x72, 0x3e, 0x34, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, + 0x69, 0x74, 0x35, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x25, 0x3c, 0x62, 0x72, 0x3e, 0x35, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x74, 0x36, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x5e, + 0x3c, 0x62, 0x72, 0x3e, 0x36, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, + 0x69, 0x74, 0x37, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x26, 0x3c, 0x62, 0x72, 0x3e, 0x37, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x74, 0x38, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x2a, + 0x3c, 0x62, 0x72, 0x3e, 0x38, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, + 0x69, 0x74, 0x39, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x28, 0x3c, 0x62, 0x72, 0x3e, 0x39, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x74, 0x30, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x29, + 0x3c, 0x62, 0x72, 0x3e, 0x30, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4d, 0x69, 0x6e, + 0x75, 0x73, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x5f, 0x3c, 0x62, 0x72, 0x3e, 0x2d, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x2b, 0x3c, 0x62, + 0x72, 0x3e, 0x3d, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x42, 0x61, 0x63, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x42, 0x61, 0x63, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3a, 0x20, 0x32, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x49, 0x6e, 0x73, 0x65, + 0x72, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x22, + 0x20, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x48, 0x6f, 0x6d, 0x65, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x48, 0x6f, 0x6d, + 0x65, 0x22, 0x20, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x50, 0x61, 0x67, 0x65, 0x55, 0x70, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x50, 0x61, 0x67, 0x65, 0x3c, 0x62, 0x72, 0x3e, 0x55, + 0x70, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x4c, 0x6f, 0x63, 0x6b, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x4e, 0x75, 0x6d, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x70, + 0x61, 0x64, 0x44, 0x69, 0x76, 0x69, 0x64, 0x65, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x2f, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, 0x4d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x2a, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, 0x53, 0x75, 0x62, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x2d, 0x22, 0x7d, 0xa, 0x9, + 0x5d, 0x2c, 0xa, 0x9, 0x5b, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x54, 0x61, 0x62, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x61, + 0x62, 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, + 0x20, 0x31, 0x2e, 0x35, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x51, 0x22, + 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x51, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x57, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x57, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x4b, 0x65, 0x79, 0x45, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, + 0x65, 0x79, 0x52, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x52, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, + 0x54, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x54, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x59, 0x22, + 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x59, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x55, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x55, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x4b, 0x65, 0x79, 0x49, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x49, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, + 0x65, 0x79, 0x4f, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x4f, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, + 0x50, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x50, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x42, 0x72, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x7b, 0x3c, 0x62, + 0x72, 0x3e, 0x5b, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x42, 0x72, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x7d, 0x3c, + 0x62, 0x72, 0x3e, 0x5d, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x42, 0x61, 0x63, 0x6b, + 0x73, 0x6c, 0x61, 0x73, 0x68, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x7c, 0x3c, 0x62, 0x72, + 0x3e, 0x5c, 0x5c, 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x20, 0x31, 0x2e, 0x35, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x45, 0x6e, 0x64, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x6e, 0x64, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x50, 0x61, 0x67, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x22, + 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x50, 0x61, 0x67, 0x65, 0x3c, 0x62, 0x72, 0x3e, 0x44, 0x6f, + 0x77, 0x6e, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, + 0x37, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x48, 0x6f, 0x6d, 0x65, 0x3c, 0x62, 0x72, 0x3e, + 0x37, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, 0x38, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x55, 0x70, 0x3c, 0x62, 0x72, 0x3e, 0x38, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, 0x39, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x50, 0x67, + 0x55, 0x70, 0x3c, 0x62, 0x72, 0x3e, 0x39, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, + 0x75, 0x6d, 0x70, 0x61, 0x64, 0x41, 0x64, 0x64, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x2b, + 0x22, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, + 0x20, 0x32, 0x7d, 0xa, 0x9, 0x5d, 0x2c, 0xa, 0x9, 0x5b, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x43, + 0x61, 0x70, 0x73, 0x4c, 0x6f, 0x63, 0x6b, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x61, + 0x70, 0x73, 0x3c, 0x62, 0x72, 0x3e, 0x4c, 0x6f, 0x63, 0x6b, + 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, + 0x32, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x4b, 0x65, 0x79, 0x41, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x4b, 0x65, 0x79, 0x53, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, + 0x79, 0x44, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x44, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x46, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x46, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x47, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x4b, 0x65, 0x79, 0x48, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x48, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x4b, 0x65, 0x79, 0x4a, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4a, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, + 0x79, 0x4b, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x4b, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x4c, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x4c, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x53, 0x65, 0x6d, 0x69, 0x63, 0x6f, + 0x6c, 0x6f, 0x6e, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x3a, 0x3c, 0x62, 0x72, 0x3e, 0x3b, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x5c, 0x22, + 0x3c, 0x62, 0x72, 0x3e, 0x5c, 0x27, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x45, 0x6e, + 0x74, 0x65, 0x72, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x22, + 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x32, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3a, 0x20, 0x33, 0x2e, 0x31, 0x37, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, + 0x70, 0x61, 0x64, 0x34, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4c, 0x65, 0x66, 0x74, 0x3c, + 0x62, 0x72, 0x3e, 0x34, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x70, + 0x61, 0x64, 0x35, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x35, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, + 0x70, 0x61, 0x64, 0x36, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x52, 0x69, 0x67, 0x68, 0x74, + 0x3c, 0x62, 0x72, 0x3e, 0x36, 0x22, 0x7d, 0xa, 0x9, 0x5d, + 0x2c, 0xa, 0x9, 0x5b, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x53, 0x68, 0x69, 0x66, 0x74, 0x4c, 0x65, + 0x66, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x53, 0x68, 0x69, 0x66, 0x74, 0x22, 0x2c, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x2e, + 0x35, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x4b, 0x65, 0x79, 0x5a, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x5a, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x4b, 0x65, 0x79, 0x58, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x58, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, + 0x79, 0x43, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x43, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x56, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x56, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x42, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x42, + 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, + 0x20, 0x22, 0x4b, 0x65, 0x79, 0x4e, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4e, 0x22, 0x7d, + 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, + 0x4b, 0x65, 0x79, 0x4d, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4d, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x5c, 0x3c, 0x3c, 0x62, 0x72, 0x3e, + 0x2c, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x22, + 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x5c, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x2e, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x53, + 0x6c, 0x61, 0x73, 0x68, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x3f, 0x3c, 0x62, 0x72, 0x3e, + 0x2f, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x53, 0x68, 0x69, 0x66, 0x74, 0x52, 0x69, + 0x67, 0x68, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x68, 0x69, 0x66, 0x74, 0x22, + 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x32, + 0x2e, 0x36, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, + 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x41, 0x72, 0x72, 0x6f, + 0x77, 0x55, 0x70, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x55, 0x70, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, 0x31, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, + 0x6e, 0x64, 0x3c, 0x62, 0x72, 0x3e, 0x31, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, + 0x75, 0x6d, 0x70, 0x61, 0x64, 0x32, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x6f, 0x77, + 0x6e, 0x3c, 0x62, 0x72, 0x3e, 0x32, 0x22, 0x7d, 0x2c, 0xa, + 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, 0x75, + 0x6d, 0x70, 0x61, 0x64, 0x33, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x50, 0x67, 0x44, 0x6e, + 0x3c, 0x62, 0x72, 0x3e, 0x33, 0x22, 0x7d, 0x2c, 0xa, 0x9, + 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, + 0x70, 0x61, 0x64, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, + 0x6e, 0x74, 0x65, 0x72, 0x22, 0x2c, 0x20, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x3a, 0x20, 0x32, 0x7d, 0xa, 0x9, 0x5d, + 0x2c, 0xa, 0x9, 0x5b, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x4c, 0x65, 0x66, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3a, 0x20, 0x32, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x4d, 0x65, 0x74, 0x61, 0x4c, 0x65, + 0x66, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x4d, 0x65, 0x74, 0x61, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x41, + 0x6c, 0x74, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x2c, 0x20, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x6c, 0x74, + 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, + 0x31, 0x2e, 0x35, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, + 0x64, 0x3a, 0x20, 0x22, 0x53, 0x70, 0x61, 0x63, 0x65, 0x22, + 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x22, 0x2c, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3a, 0x20, 0x36, 0x2e, 0x34, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x41, + 0x6c, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x22, 0x2c, 0x20, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x6c, + 0x74, 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, + 0x20, 0x31, 0x2e, 0x35, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x69, 0x67, 0x68, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4d, 0x65, 0x74, 0x61, 0x22, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x69, + 0x67, 0x68, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x22, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, + 0x20, 0x32, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4c, 0x65, + 0x66, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x4c, 0x65, 0x66, 0x74, 0x22, 0x7d, 0x2c, + 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, 0x22, 0x41, + 0x72, 0x72, 0x6f, 0x77, 0x44, 0x6f, 0x77, 0x6e, 0x22, 0x2c, + 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, + 0x6f, 0x77, 0x6e, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, + 0x69, 0x64, 0x3a, 0x20, 0x22, 0x41, 0x72, 0x72, 0x6f, 0x77, + 0x52, 0x69, 0x67, 0x68, 0x74, 0x22, 0x2c, 0x20, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x52, 0x69, 0x67, 0x68, + 0x74, 0x22, 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, + 0x3a, 0x20, 0x22, 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, 0x30, + 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x49, 0x6e, 0x73, 0x3c, 0x62, 0x72, 0x3e, 0x30, 0x22, + 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x32, + 0x7d, 0x2c, 0xa, 0x9, 0x9, 0x7b, 0x69, 0x64, 0x3a, 0x20, + 0x22, 0x4e, 0x75, 0x6d, 0x70, 0x61, 0x64, 0x44, 0x65, 0x63, + 0x69, 0x6d, 0x61, 0x6c, 0x22, 0x2c, 0x20, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x65, 0x6c, 0x3c, 0x62, + 0x72, 0x3e, 0x2e, 0x22, 0x7d, 0xa, 0x9, 0x5d, 0x2c, 0xa, + 0x5d, 0x3b, 0xa, 0xa, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x2e, 0x73, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x28, 0x22, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, + 0x73, 0x28, 0x29, 0x3b, 0x22, 0x2c, 0x32, 0x30, 0x30, 0x30, + 0x29, 0x3b, 0xa, 0xa, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x22, 0x6b, + 0x65, 0x79, 0x64, 0x6f, 0x77, 0x6e, 0x22, 0x2c, 0x20, 0x6f, + 0x6e, 0x4b, 0x65, 0x79, 0x44, 0x6f, 0x77, 0x6e, 0x2c, 0x20, + 0x74, 0x72, 0x75, 0x65, 0x29, 0x3b, 0xa, 0x77, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x28, 0x22, 0x6b, 0x65, 0x79, 0x75, 0x70, 0x22, 0x2c, 0x20, + 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x2c, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x29, 0x3b, 0xa, 0xa, 0x77, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x2e, 0x6f, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x20, 0x3d, 0x20, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, + 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0xa, 0x9, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x28, + 0x22, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x29, 0x3b, + 0xa, 0x9, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, + 0x79, 0x73, 0x28, 0x22, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x22, 0x29, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, + 0x4b, 0x65, 0x79, 0x44, 0x6f, 0x77, 0x6e, 0x28, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x69, 0x66, + 0x20, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x65, 0x64, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x20, 0x2f, 0x2f, + 0x20, 0x44, 0x6f, 0x20, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, + 0x67, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, + 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x70, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0xa, 0x9, 0x7d, 0xa, + 0x9, 0xa, 0x9, 0x70, 0x72, 0x65, 0x73, 0x73, 0x4b, 0x65, + 0x79, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x29, 0x3b, 0xa, 0xa, 0x9, 0x2f, 0x2f, 0x20, + 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x61, + 0x76, 0x6f, 0x69, 0x64, 0x20, 0x69, 0x74, 0x20, 0x62, 0x65, + 0x69, 0x6e, 0x67, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x64, 0x20, 0x74, 0x77, 0x69, 0x63, 0x65, 0xa, 0x9, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x28, + 0x29, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x4b, 0x65, 0x79, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x20, + 0x7b, 0xa, 0x9, 0x69, 0x66, 0x20, 0x28, 0x6b, 0x65, 0x79, + 0x73, 0x2e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, + 0x28, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x29, 0x20, 0x7b, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x20, 0x7d, 0xa, + 0xa, 0x9, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x75, 0x73, + 0x68, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x3b, 0xa, 0xa, + 0x9, 0x73, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x28, + 0x6b, 0x65, 0x79, 0x73, 0x29, 0x3b, 0xa, 0x7d, 0xa, 0xa, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, + 0x6e, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x28, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x69, 0x66, 0x20, + 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x65, 0x64, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x20, 0x2f, 0x2f, 0x20, + 0x44, 0x6f, 0x20, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, + 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x6c, + 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x70, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x65, 0x64, 0xa, 0x9, 0x20, 0x7d, 0xa, + 0xa, 0x9, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4b, + 0x65, 0x79, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x29, 0x3b, 0xa, 0xa, 0x9, 0x2f, 0x2f, + 0x20, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, + 0x61, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x69, 0x74, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x64, 0x20, 0x74, 0x77, 0x69, 0x63, 0x65, 0xa, 0x9, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x28, 0x29, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x28, 0x63, 0x6f, 0x64, + 0x65, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x69, 0x66, 0x20, 0x28, + 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x73, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x29, + 0x20, 0x7b, 0xa, 0x9, 0x9, 0x6b, 0x65, 0x79, 0x73, 0x2e, + 0x73, 0x70, 0x6c, 0x69, 0x63, 0x65, 0x28, 0x6b, 0x65, 0x79, + 0x73, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x28, + 0x63, 0x6f, 0x64, 0x65, 0x29, 0x2c, 0x31, 0x29, 0x3b, 0xa, + 0x9, 0x7d, 0xa, 0xa, 0x9, 0x73, 0x65, 0x6e, 0x64, 0x4b, + 0x65, 0x79, 0x73, 0x28, 0x6b, 0x65, 0x79, 0x73, 0x29, 0x3b, + 0xa, 0x7d, 0xa, 0xa, 0xa, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x4b, 0x65, + 0x79, 0x73, 0x28, 0x63, 0x75, 0x72, 0x4b, 0x65, 0x79, 0x73, + 0x29, 0x20, 0x7b, 0xa, 0x9, 0x63, 0x6f, 0x6e, 0x73, 0x74, + 0x20, 0x75, 0x72, 0x6c, 0x3d, 0x22, 0x73, 0x65, 0x6e, 0x64, + 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x63, 0x67, 0x69, 0x3f, 0x6b, + 0x65, 0x79, 0x73, 0x3d, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x63, + 0x61, 0x74, 0x28, 0x63, 0x75, 0x72, 0x4b, 0x65, 0x79, 0x73, + 0x29, 0x3b, 0xa, 0x9, 0x66, 0x65, 0x74, 0x63, 0x68, 0x71, + 0x75, 0x65, 0x75, 0x65, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x28, + 0x75, 0x72, 0x6c, 0x29, 0x3b, 0xa, 0x9, 0x63, 0x6f, 0x6e, + 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x66, + 0x65, 0x74, 0x63, 0x68, 0x71, 0x75, 0x65, 0x75, 0x65, 0x29, + 0x3b, 0xa, 0x9, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x64, 0x6f, + 0x77, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x22, 0x29, 0xa, 0x9, + 0x9, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, + 0x4c, 0x20, 0x3d, 0x20, 0x63, 0x75, 0x72, 0x4b, 0x65, 0x79, + 0x73, 0x3b, 0xa, 0x9, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x6b, + 0x65, 0x79, 0x73, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x22, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x22, 0x29, 0x3b, 0xa, + 0x9, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x6c, 0x65, 0x74, 0x20, + 0x6b, 0x65, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x75, 0x72, + 0x4b, 0x65, 0x79, 0x73, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x6b, 0x65, 0x79, 0x44, 0x69, 0x76, 0x20, 0x3d, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, + 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, + 0x49, 0x64, 0x28, 0x6b, 0x65, 0x79, 0x29, 0x3b, 0xa, 0x9, + 0x9, 0x6b, 0x65, 0x79, 0x44, 0x69, 0x76, 0x2e, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x61, 0x64, + 0x64, 0x28, 0x22, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, + 0x22, 0x29, 0x3b, 0xa, 0x9, 0x7d, 0xa, 0x9, 0x66, 0x6f, + 0x72, 0x20, 0x28, 0x6c, 0x65, 0x74, 0x20, 0x6b, 0x65, 0x79, + 0x20, 0x6f, 0x66, 0x20, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x6b, + 0x65, 0x79, 0x73, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x69, + 0x66, 0x20, 0x28, 0x21, 0x63, 0x75, 0x72, 0x4b, 0x65, 0x79, + 0x73, 0x2e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, + 0x28, 0x6b, 0x65, 0x79, 0x2e, 0x69, 0x64, 0x29, 0x29, 0x20, + 0x7b, 0xa, 0x9, 0x9, 0x9, 0x6b, 0x65, 0x79, 0x2e, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x72, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x28, 0x22, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x22, 0x29, 0x3b, 0xa, 0x9, 0x9, + 0x7d, 0xa, 0x9, 0x7d, 0xa, 0x9, 0x69, 0x66, 0x20, 0x28, + 0x66, 0x65, 0x74, 0x63, 0x68, 0x71, 0x75, 0x65, 0x75, 0x65, + 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3d, 0x3d, + 0x20, 0x31, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x72, 0x75, + 0x6e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x28, 0x29, 0x3b, 0xa, + 0x9, 0x7d, 0xa, 0x7d, 0xa, 0xa, 0x61, 0x73, 0x79, 0x6e, + 0x63, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x72, 0x75, 0x6e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x28, + 0x29, 0x20, 0x7b, 0xa, 0x9, 0x63, 0x6f, 0x6e, 0x73, 0x74, + 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x65, 0x74, + 0x63, 0x68, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5b, 0x30, 0x5d, + 0x3b, 0xa, 0x9, 0x61, 0x77, 0x61, 0x69, 0x74, 0x20, 0x66, + 0x65, 0x74, 0x63, 0x68, 0x28, 0x75, 0x72, 0x6c, 0x29, 0x3b, + 0xa, 0x9, 0x66, 0x65, 0x74, 0x63, 0x68, 0x71, 0x75, 0x65, + 0x75, 0x65, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x29, + 0x3b, 0xa, 0x9, 0x69, 0x66, 0x20, 0x28, 0x66, 0x65, 0x74, + 0x63, 0x68, 0x71, 0x75, 0x65, 0x75, 0x65, 0x2e, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x20, + 0x7b, 0xa, 0x9, 0x9, 0x72, 0x75, 0x6e, 0x51, 0x75, 0x65, + 0x75, 0x65, 0x28, 0x29, 0x3b, 0xa, 0x9, 0x7d, 0xa, 0x7d, + 0xa, 0xa, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x28, 0x29, 0x20, + 0x7b, 0xa, 0x9, 0x6c, 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x46, 0x72, 0x61, 0x6d, + 0x65, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x69, + 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x22, 0x29, 0x3b, 0xa, 0x9, 0x6c, 0x65, + 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x44, 0x69, 0x76, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, + 0x28, 0x22, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x73, 0x22, 0x29, 0x3b, 0xa, 0x9, 0x69, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x69, 0x76, 0x2e, + 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x3d, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x69, 0x6e, + 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x3b, 0xa, 0x7d, + 0xa, 0xa, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, + 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x28, 0x29, + 0x20, 0x7b, 0xa, 0x9, 0x6c, 0x65, 0x74, 0x20, 0x69, 0x6e, + 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, + 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x46, + 0x72, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x3b, 0xa, 0x9, 0x69, + 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x72, 0x65, 0x6c, + 0x6f, 0x61, 0x64, 0x28, 0x74, 0x72, 0x75, 0x65, 0x29, 0x3b, + 0xa, 0x7d, 0xa, 0xa, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, + 0x65, 0x79, 0x73, 0x28, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x5f, 0x69, 0x64, 0x29, 0x20, 0x7b, 0xa, 0x9, + 0x6c, 0x65, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x44, 0x69, 0x76, 0x20, 0x3d, 0x20, 0x64, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, + 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, + 0x64, 0x28, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x5f, 0x69, 0x64, 0x29, 0x3b, 0xa, 0x9, 0x66, 0x6f, 0x72, + 0x20, 0x28, 0x6c, 0x65, 0x74, 0x20, 0x72, 0x6f, 0x77, 0x20, + 0x6f, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x69, 0x73, + 0x74, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x6c, 0x65, 0x74, + 0x20, 0x6e, 0x65, 0x77, 0x52, 0x6f, 0x77, 0x20, 0x3d, 0x20, + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x28, 0x22, 0x64, 0x69, 0x76, 0x22, 0x29, 0x3b, + 0xa, 0x9, 0x9, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x44, 0x69, 0x76, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, + 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x28, 0x6e, 0x65, 0x77, + 0x52, 0x6f, 0x77, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x66, 0x6f, + 0x72, 0x20, 0x28, 0x6c, 0x65, 0x74, 0x20, 0x6b, 0x65, 0x79, + 0x20, 0x6f, 0x66, 0x20, 0x72, 0x6f, 0x77, 0x29, 0x20, 0x7b, + 0xa, 0x9, 0x9, 0x9, 0x6c, 0x65, 0x74, 0x20, 0x6e, 0x65, + 0x77, 0x44, 0x69, 0x76, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, + 0x22, 0x64, 0x69, 0x76, 0x22, 0x29, 0x3b, 0xa, 0x9, 0x9, + 0x9, 0x69, 0x66, 0x20, 0x28, 0x6b, 0x65, 0x79, 0x2e, 0x69, + 0x64, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x9, 0x9, 0x6e, + 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, 0x69, 0x64, 0x20, 0x3d, + 0x20, 0x6b, 0x65, 0x79, 0x2e, 0x69, 0x64, 0x3b, 0xa, 0x9, + 0x9, 0x9, 0x9, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, + 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x3d, 0x20, 0x6b, 0x65, 0x79, 0x2e, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x3b, 0xa, 0x9, 0x9, 0x9, 0x9, 0x6e, 0x65, 0x77, + 0x44, 0x69, 0x76, 0x2e, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4e, + 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x6b, 0x65, 0x79, + 0x22, 0x3b, 0xa, 0x9, 0x9, 0x9, 0x9, 0x6e, 0x65, 0x77, + 0x44, 0x69, 0x76, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x28, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x64, 0x6f, 0x77, + 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x9, 0x9, 0x9, 0x70, 0x72, 0x65, 0x73, 0x73, 0x4b, 0x65, + 0x79, 0x28, 0x6b, 0x65, 0x79, 0x2e, 0x69, 0x64, 0x29, 0x3b, + 0x20, 0x7d, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x9, 0x9, 0x6e, + 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, 0x61, 0x64, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x65, 0x72, 0x28, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x75, + 0x70, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x9, 0x9, 0x9, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x4b, 0x65, 0x79, 0x28, 0x6b, 0x65, 0x79, 0x2e, 0x69, 0x64, + 0x29, 0x3b, 0x20, 0x7d, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x9, + 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0xa, 0x9, + 0x9, 0x9, 0x9, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x20, + 0x3d, 0x20, 0x22, 0x6b, 0x65, 0x79, 0x20, 0x62, 0x6c, 0x61, + 0x6e, 0x6b, 0x22, 0x3b, 0xa, 0x9, 0x9, 0x9, 0x7d, 0xa, + 0x9, 0x9, 0x9, 0x6e, 0x65, 0x77, 0x52, 0x6f, 0x77, 0x2e, + 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, + 0x64, 0x28, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x29, 0x3b, + 0xa, 0x9, 0x9, 0x9, 0x69, 0x66, 0x20, 0x28, 0x6b, 0x65, + 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x29, 0x20, 0x7b, + 0xa, 0x9, 0x9, 0x9, 0x9, 0x6e, 0x65, 0x77, 0x44, 0x69, + 0x76, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x3d, 0x20, + 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x22, 0x20, 0x2b, + 0x20, 0x28, 0x6b, 0x65, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x2a, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, + 0x20, 0x29, 0x20, 0x2b, 0x20, 0x22, 0x70, 0x78, 0x3b, 0x22, + 0x3b, 0xa, 0x9, 0x9, 0x9, 0x7d, 0xa, 0x9, 0x9, 0x9, + 0x69, 0x66, 0x20, 0x28, 0x6b, 0x65, 0x79, 0x2e, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x9, 0x9, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x3a, 0x22, 0x20, 0x2b, 0x20, 0x28, + 0x6b, 0x65, 0x79, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x2a, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x29, 0x20, 0x2b, 0x20, 0x22, 0x70, 0x78, 0x3b, 0x20, + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x3b, 0x22, 0x3b, 0xa, 0x9, 0x9, 0x9, 0x7d, + 0xa, 0x9, 0x9, 0x7d, 0xa, 0x9, 0x7d, 0xa, 0x7d, 0xa, + 0xa, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x72, + 0x6f, 0x73, 0x28, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x5f, 0x69, + 0x64, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x6c, 0x65, 0x74, 0x20, + 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x44, 0x69, 0x76, 0x20, 0x3d, + 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, + 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x42, 0x79, 0x49, 0x64, 0x28, 0x6d, 0x61, 0x63, 0x72, 0x6f, + 0x5f, 0x69, 0x64, 0x29, 0x3b, 0xa, 0x9, 0x66, 0x6f, 0x72, + 0x20, 0x28, 0x6c, 0x65, 0x74, 0x20, 0x6d, 0x61, 0x63, 0x72, + 0x6f, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x61, 0x63, 0x72, 0x6f, + 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x29, 0x20, 0x7b, 0xa, 0x9, + 0x9, 0x6c, 0x65, 0x74, 0x20, 0x6e, 0x65, 0x77, 0x44, 0x69, + 0x76, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x22, 0x64, 0x69, + 0x76, 0x22, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x6e, 0x65, 0x77, + 0x44, 0x69, 0x76, 0x2e, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x6d, + 0x61, 0x63, 0x72, 0x6f, 0x2e, 0x69, 0x64, 0x3b, 0xa, 0x9, + 0x9, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, 0x74, 0x65, + 0x78, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, + 0x3d, 0x20, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x2e, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x3b, 0xa, 0x9, 0x9, 0x6e, 0x65, 0x77, + 0x44, 0x69, 0x76, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x28, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x64, 0x6f, 0x77, + 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x9, 0x73, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x28, + 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x2e, 0x6b, 0x65, 0x79, 0x73, + 0x29, 0x3b, 0x20, 0x7d, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x6e, + 0x65, 0x77, 0x44, 0x69, 0x76, 0x2e, 0x61, 0x64, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x65, 0x72, 0x28, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x75, + 0x70, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, + 0x9, 0x73, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x28, + 0x5b, 0x5d, 0x29, 0x3b, 0x20, 0x7d, 0x29, 0x3b, 0xa, 0x9, + 0x9, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x44, 0x69, 0x76, 0x2e, + 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x69, 0x6c, + 0x64, 0x28, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x76, 0x29, 0x3b, + 0xa, 0x9, 0x7d, 0xa, 0x7d, 0xa, 0xa, 0x3c, 0x2f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x3e, 0xa, 0xa, 0x3c, 0x2f, + 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0xa, 0x3c, 0x62, 0x6f, + 0x64, 0x79, 0x3e, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x22, 0x3e, 0xa, 0x9, 0x3c, + 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x6b, 0x65, + 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x22, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x69, 0x64, 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x3e, 0x3c, 0x2f, 0x64, + 0x69, 0x76, 0x3e, 0xa, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, + 0x22, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x3e, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x69, + 0x6e, 0x66, 0x6f, 0x22, 0x3e, 0xa, 0x9, 0x3c, 0x64, 0x69, + 0x76, 0x3e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x6c, + 0x79, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x73, 0x3a, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, + 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x4b, 0x65, 0x79, 0x73, + 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, 0x3c, 0x64, 0x69, + 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, + 0x22, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x77, 0x69, 0x66, 0x69, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x20, 0x57, 0x69, 0x2d, 0x46, + 0x69, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x64, + 0x69, 0x76, 0x3e, 0xa, 0x9, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, + 0x75, 0x22, 0x3e, 0xa, 0x9, 0x9, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x72, 0x65, 0x62, 0x6f, 0x6f, + 0x74, 0x2e, 0x63, 0x67, 0x69, 0x22, 0x3e, 0x52, 0x65, 0x62, + 0x6f, 0x6f, 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x9, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x3c, 0x2f, 0x64, 0x69, + 0x76, 0x3e, 0xa, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, + 0x64, 0x3d, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, + 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3e, 0xa, 0x9, + 0x3c, 0x69, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x64, + 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x20, 0x73, 0x72, + 0x63, 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0xa, 0x9, 0x9, 0x6f, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3d, + 0x22, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x28, 0x29, 0x3b, + 0x22, 0x3e, 0x3c, 0x2f, 0x69, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x3e, 0xa, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, + 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0xa, 0x3c, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, }; + +static const unsigned char data_success_html[] = { + /* /success.html */ + 0x2f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0x3c, + 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x68, + 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, + 0xa, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x53, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x3c, 0x2f, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x73, 0x74, 0x79, 0x6c, + 0x65, 0x3e, 0xa, 0x73, 0x70, 0x61, 0x6e, 0x2e, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x20, 0x7b, 0xa, 0x9, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x69, 0x6e, 0x6c, 0x69, + 0x6e, 0x65, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3b, 0xa, + 0x7d, 0xa, 0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, + 0xa, 0xa, 0x3c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3e, + 0xa, 0x9, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0xa, 0x9, 0x73, + 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x28, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x28, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x9, 0x76, + 0x61, 0x72, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, + 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x22, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x9, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x2d, 0x3b, 0xa, 0x9, + 0x9, 0x9, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x2e, + 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x54, 0x65, 0x78, 0x74, 0x3d, + 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0xa, 0x9, 0x9, + 0x9, 0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0xa, 0x9, + 0x9, 0x9, 0x9, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, + 0x20, 0x22, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3b, 0xa, 0x9, 0x9, 0x9, 0x7d, 0xa, + 0x9, 0x9, 0x7d, 0x2c, 0x20, 0x31, 0x30, 0x30, 0x30, 0x29, + 0x3b, 0xa, 0x3c, 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, + 0xa, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0xa, 0x3c, + 0x70, 0x3e, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x3c, + 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x70, 0x3e, 0x52, 0x65, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, + 0x69, 0x6e, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, + 0x64, 0x3d, 0x22, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3e, + 0x31, 0x35, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x2e, + 0x2e, 0x2e, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x2f, + 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x68, + 0x74, 0x6d, 0x6c, 0x3e, 0xa, }; + +const struct fsdata_file file_fsdata_c[] = {{NULL, data_fsdata_c, data_fsdata_c + 10, sizeof(data_fsdata_c) - 10, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}}; + +const struct fsdata_file file_indicators_shtml[] = {{file_fsdata_c, data_indicators_shtml, data_indicators_shtml + 18, sizeof(data_indicators_shtml) - 18, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}}; + +const struct fsdata_file file_wifi_shtml[] = {{file_indicators_shtml, data_wifi_shtml, data_wifi_shtml + 12, sizeof(data_wifi_shtml) - 12, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}}; + +const struct fsdata_file file_index_html[] = {{file_wifi_shtml, data_index_html, data_index_html + 12, sizeof(data_index_html) - 12, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}}; + +const struct fsdata_file file_success_html[] = {{file_index_html, data_success_html, data_success_html + 14, sizeof(data_success_html) - 14, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}}; + +#define FS_ROOT file_success_html + +#define FS_NUMFILES 5 diff --git a/parse_keys.c b/parse_keys.c new file mode 100644 index 0000000..ac6d186 --- /dev/null +++ b/parse_keys.c @@ -0,0 +1,64 @@ +#include +#include + +#include "pico/stdlib.h" +#include "tusb.h" + +#include "parse_keys.h" +#include "usb_descriptors.h" + +void parse_key_list(char * keys) { + uint8_t keypos = 2; + uint8_t code = 0x00; + static unsigned char boot_report[8]; + memset(boot_report, 0x00, 8); + + char * token = strtok(keys, ","); + while (token != NULL) { + code = parse_key_single(token); + if (code && keypos < 9) { + boot_report[keypos] = code; + keypos++; + } + if (code == 0x00) { + code = parse_mod(token); + if (code) { + boot_report[0] = boot_report[0] | code; + } + } + token = strtok(NULL, ","); + } + + printf("HID report: "); + for(int i=0; i<8; i++){ + printf("%02X ",boot_report[i]); + } + printf("\n"); + + tud_hid_report(REPORT_ID_KEYBOARD, boot_report, 8); +} + +uint8_t parse_key_single(char * key) { + //printf("single key: %s\n", key); + + for (int i=0; i < NKEYS; i++) { + keycode_dict * keycode = &keytable[i]; + if (strcmp(keycode->key, key) == 0){ + //printf("key found"); + return keycode->val; + } + } + return 0x00; +} + +uint8_t parse_mod(char * key) { + for (int i=0; i < NMODS; i++) { + keycode_dict * modcode = &modtable[i]; + if (strcmp(modcode->key, key) == 0){ + //printf("key found"); + return modcode->val; + } + } + return 0x00; +} + diff --git a/parse_keys.h b/parse_keys.h new file mode 100644 index 0000000..33708a9 --- /dev/null +++ b/parse_keys.h @@ -0,0 +1,393 @@ +#ifndef PARSE_KEYS_H_ +#define PRASE_KEYS_H_ + +static unsigned char boot_buf[8]; + +void parse_key_list(char * keys); +uint8_t parse_key_single(char * key); +uint8_t parse_mod(char * key); + +typedef struct { char * key; uint8_t val; } keycode_dict; + +#define KEY_MOD_LCTRL 0x01 +#define KEY_MOD_LSHIFT 0x02 +#define KEY_MOD_LALT 0x04 +#define KEY_MOD_LMETA 0x08 +#define KEY_MOD_RCTRL 0x10 +#define KEY_MOD_RSHIFT 0x20 +#define KEY_MOD_RALT 0x40 +#define KEY_MOD_RMETA 0x80 + +/** + * Scan codes - last N slots in the HID report (usually 6). + * 0x00 if no key pressed. + * + * If more than N keys are pressed, the HID reports + * KEY_ERR_OVF in all slots to indicate this condition. + */ + +#define KEY_NONE 0x00 // No key pressed +#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key") +// 0x02 // Keyboard POST Fail +// 0x03 // Keyboard Error Undefined +#define KEY_A 0x04 // Keyboard a and A +#define KEY_B 0x05 // Keyboard b and B +#define KEY_C 0x06 // Keyboard c and C +#define KEY_D 0x07 // Keyboard d and D +#define KEY_E 0x08 // Keyboard e and E +#define KEY_F 0x09 // Keyboard f and F +#define KEY_G 0x0a // Keyboard g and G +#define KEY_H 0x0b // Keyboard h and H +#define KEY_I 0x0c // Keyboard i and I +#define KEY_J 0x0d // Keyboard j and J +#define KEY_K 0x0e // Keyboard k and K +#define KEY_L 0x0f // Keyboard l and L +#define KEY_M 0x10 // Keyboard m and M +#define KEY_N 0x11 // Keyboard n and N +#define KEY_O 0x12 // Keyboard o and O +#define KEY_P 0x13 // Keyboard p and P +#define KEY_Q 0x14 // Keyboard q and Q +#define KEY_R 0x15 // Keyboard r and R +#define KEY_S 0x16 // Keyboard s and S +#define KEY_T 0x17 // Keyboard t and T +#define KEY_U 0x18 // Keyboard u and U +#define KEY_V 0x19 // Keyboard v and V +#define KEY_W 0x1a // Keyboard w and W +#define KEY_X 0x1b // Keyboard x and X +#define KEY_Y 0x1c // Keyboard y and Y +#define KEY_Z 0x1d // Keyboard z and Z + +#define KEY_1 0x1e // Keyboard 1 and ! +#define KEY_2 0x1f // Keyboard 2 and @ +#define KEY_3 0x20 // Keyboard 3 and # +#define KEY_4 0x21 // Keyboard 4 and $ +#define KEY_5 0x22 // Keyboard 5 and % +#define KEY_6 0x23 // Keyboard 6 and ^ +#define KEY_7 0x24 // Keyboard 7 and & +#define KEY_8 0x25 // Keyboard 8 and * +#define KEY_9 0x26 // Keyboard 9 and ( +#define KEY_0 0x27 // Keyboard 0 and ) + +#define KEY_ENTER 0x28 // Keyboard Return (ENTER) +#define KEY_ESC 0x29 // Keyboard ESCAPE +#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace) +#define KEY_TAB 0x2b // Keyboard Tab +#define KEY_SPACE 0x2c // Keyboard Spacebar +#define KEY_MINUS 0x2d // Keyboard - and _ +#define KEY_EQUAL 0x2e // Keyboard = and + +#define KEY_LEFTBRACE 0x2f // Keyboard [ and { +#define KEY_RIGHTBRACE 0x30 // Keyboard ] and } +#define KEY_BACKSLASH 0x31 // Keyboard \ and | +#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~ +#define KEY_SEMICOLON 0x33 // Keyboard ; and : +#define KEY_APOSTROPHE 0x34 // Keyboard ' and " +#define KEY_GRAVE 0x35 // Keyboard ` and ~ +#define KEY_COMMA 0x36 // Keyboard , and < +#define KEY_DOT 0x37 // Keyboard . and > +#define KEY_SLASH 0x38 // Keyboard / and ? +#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock + +#define KEY_F1 0x3a // Keyboard F1 +#define KEY_F2 0x3b // Keyboard F2 +#define KEY_F3 0x3c // Keyboard F3 +#define KEY_F4 0x3d // Keyboard F4 +#define KEY_F5 0x3e // Keyboard F5 +#define KEY_F6 0x3f // Keyboard F6 +#define KEY_F7 0x40 // Keyboard F7 +#define KEY_F8 0x41 // Keyboard F8 +#define KEY_F9 0x42 // Keyboard F9 +#define KEY_F10 0x43 // Keyboard F10 +#define KEY_F11 0x44 // Keyboard F11 +#define KEY_F12 0x45 // Keyboard F12 + +#define KEY_SYSRQ 0x46 // Keyboard Print Screen +#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock +#define KEY_PAUSE 0x48 // Keyboard Pause +#define KEY_INSERT 0x49 // Keyboard Insert +#define KEY_HOME 0x4a // Keyboard Home +#define KEY_PAGEUP 0x4b // Keyboard Page Up +#define KEY_DELETE 0x4c // Keyboard Delete Forward +#define KEY_END 0x4d // Keyboard End +#define KEY_PAGEDOWN 0x4e // Keyboard Page Down +#define KEY_RIGHT 0x4f // Keyboard Right Arrow +#define KEY_LEFT 0x50 // Keyboard Left Arrow +#define KEY_DOWN 0x51 // Keyboard Down Arrow +#define KEY_UP 0x52 // Keyboard Up Arrow + +#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear +#define KEY_KPSLASH 0x54 // Keypad / +#define KEY_KPASTERISK 0x55 // Keypad * +#define KEY_KPMINUS 0x56 // Keypad - +#define KEY_KPPLUS 0x57 // Keypad + +#define KEY_KPENTER 0x58 // Keypad ENTER +#define KEY_KP1 0x59 // Keypad 1 and End +#define KEY_KP2 0x5a // Keypad 2 and Down Arrow +#define KEY_KP3 0x5b // Keypad 3 and PageDn +#define KEY_KP4 0x5c // Keypad 4 and Left Arrow +#define KEY_KP5 0x5d // Keypad 5 +#define KEY_KP6 0x5e // Keypad 6 and Right Arrow +#define KEY_KP7 0x5f // Keypad 7 and Home +#define KEY_KP8 0x60 // Keypad 8 and Up Arrow +#define KEY_KP9 0x61 // Keypad 9 and Page Up +#define KEY_KP0 0x62 // Keypad 0 and Insert +#define KEY_KPDOT 0x63 // Keypad . and Delete + +#define KEY_102ND 0x64 // Keyboard Non-US \ and | +#define KEY_COMPOSE 0x65 // Keyboard Application +#define KEY_POWER 0x66 // Keyboard Power +#define KEY_KPEQUAL 0x67 // Keypad = + +#define KEY_F13 0x68 // Keyboard F13 +#define KEY_F14 0x69 // Keyboard F14 +#define KEY_F15 0x6a // Keyboard F15 +#define KEY_F16 0x6b // Keyboard F16 +#define KEY_F17 0x6c // Keyboard F17 +#define KEY_F18 0x6d // Keyboard F18 +#define KEY_F19 0x6e // Keyboard F19 +#define KEY_F20 0x6f // Keyboard F20 +#define KEY_F21 0x70 // Keyboard F21 +#define KEY_F22 0x71 // Keyboard F22 +#define KEY_F23 0x72 // Keyboard F23 +#define KEY_F24 0x73 // Keyboard F24 + +#define KEY_OPEN 0x74 // Keyboard Execute +#define KEY_HELP 0x75 // Keyboard Help +#define KEY_PROPS 0x76 // Keyboard Menu +#define KEY_FRONT 0x77 // Keyboard Select +#define KEY_STOP 0x78 // Keyboard Stop +#define KEY_AGAIN 0x79 // Keyboard Again +#define KEY_UNDO 0x7a // Keyboard Undo +#define KEY_CUT 0x7b // Keyboard Cut +#define KEY_COPY 0x7c // Keyboard Copy +#define KEY_PASTE 0x7d // Keyboard Paste +#define KEY_FIND 0x7e // Keyboard Find +#define KEY_MUTE 0x7f // Keyboard Mute +#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up +#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down +// 0x82 Keyboard Locking Caps Lock +// 0x83 Keyboard Locking Num Lock +// 0x84 Keyboard Locking Scroll Lock +#define KEY_KPCOMMA 0x85 // Keypad Comma +// 0x86 Keypad Equal Sign +#define KEY_RO 0x87 // Keyboard International1 +#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2 +#define KEY_YEN 0x89 // Keyboard International3 +#define KEY_HENKAN 0x8a // Keyboard International4 +#define KEY_MUHENKAN 0x8b // Keyboard International5 +#define KEY_KPJPCOMMA 0x8c // Keyboard International6 +// 0x8d Keyboard International7 +// 0x8e Keyboard International8 +// 0x8f Keyboard International9 +#define KEY_HANGEUL 0x90 // Keyboard LANG1 +#define KEY_HANJA 0x91 // Keyboard LANG2 +#define KEY_KATAKANA 0x92 // Keyboard LANG3 +#define KEY_HIRAGANA 0x93 // Keyboard LANG4 +#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5 +// 0x95 Keyboard LANG6 +// 0x96 Keyboard LANG7 +// 0x97 Keyboard LANG8 +// 0x98 Keyboard LANG9 +// 0x99 Keyboard Alternate Erase +// 0x9a Keyboard SysReq/Attention +// 0x9b Keyboard Cancel +// 0x9c Keyboard Clear +// 0x9d Keyboard Prior +// 0x9e Keyboard Return +// 0x9f Keyboard Separator +// 0xa0 Keyboard Out +// 0xa1 Keyboard Oper +// 0xa2 Keyboard Clear/Again +// 0xa3 Keyboard CrSel/Props +// 0xa4 Keyboard ExSel + +// 0xb0 Keypad 00 +// 0xb1 Keypad 000 +// 0xb2 Thousands Separator +// 0xb3 Decimal Separator +// 0xb4 Currency Unit +// 0xb5 Currency Sub-unit +#define KEY_KPLEFTPAREN 0xb6 // Keypad ( +#define KEY_KPRIGHTPAREN 0xb7 // Keypad ) +// 0xb8 Keypad { +// 0xb9 Keypad } +// 0xba Keypad Tab +// 0xbb Keypad Backspace +// 0xbc Keypad A +// 0xbd Keypad B +// 0xbe Keypad C +// 0xbf Keypad D +// 0xc0 Keypad E +// 0xc1 Keypad F +// 0xc2 Keypad XOR +// 0xc3 Keypad ^ +// 0xc4 Keypad % +// 0xc5 Keypad < +// 0xc6 Keypad > +// 0xc7 Keypad & +// 0xc8 Keypad && +// 0xc9 Keypad | +// 0xca Keypad || +// 0xcb Keypad : +// 0xcc Keypad # +// 0xcd Keypad Space +// 0xce Keypad @ +// 0xcf Keypad ! +// 0xd0 Keypad Memory Store +// 0xd1 Keypad Memory Recall +// 0xd2 Keypad Memory Clear +// 0xd3 Keypad Memory Add +// 0xd4 Keypad Memory Subtract +// 0xd5 Keypad Memory Multiply +// 0xd6 Keypad Memory Divide +// 0xd7 Keypad +/- +// 0xd8 Keypad Clear +// 0xd9 Keypad Clear Entry +// 0xda Keypad Binary +// 0xdb Keypad Octal +// 0xdc Keypad Decimal +// 0xdd Keypad Hexadecimal + +#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control +#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift +#define KEY_LEFTALT 0xe2 // Keyboard Left Alt +#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI +#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control +#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift +#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt +#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI + +#define KEY_MEDIA_PLAYPAUSE 0xe8 +#define KEY_MEDIA_STOPCD 0xe9 +#define KEY_MEDIA_PREVIOUSSONG 0xea +#define KEY_MEDIA_NEXTSONG 0xeb +#define KEY_MEDIA_EJECTCD 0xec +#define KEY_MEDIA_VOLUMEUP 0xed +#define KEY_MEDIA_VOLUMEDOWN 0xee +#define KEY_MEDIA_MUTE 0xef +#define KEY_MEDIA_WWW 0xf0 +#define KEY_MEDIA_BACK 0xf1 +#define KEY_MEDIA_FORWARD 0xf2 +#define KEY_MEDIA_STOP 0xf3 +#define KEY_MEDIA_FIND 0xf4 +#define KEY_MEDIA_SCROLLUP 0xf5 +#define KEY_MEDIA_SCROLLDOWN 0xf6 +#define KEY_MEDIA_EDIT 0xf7 +#define KEY_MEDIA_SLEEP 0xf8 +#define KEY_MEDIA_COFFEE 0xf9 +#define KEY_MEDIA_REFRESH 0xfa +#define KEY_MEDIA_CALC 0xfb + +static keycode_dict keytable[] = { + {"KeyA", KEY_A}, + {"KeyB", KEY_B}, + {"KeyC", KEY_C}, + {"KeyD", KEY_D}, + {"KeyE", KEY_E}, + {"KeyF", KEY_F}, + {"KeyG", KEY_G}, + {"KeyH", KEY_H}, + {"KeyI", KEY_I}, + {"KeyJ", KEY_J}, + {"KeyK", KEY_K}, + {"KeyL", KEY_L}, + {"KeyM", KEY_M}, + {"KeyN", KEY_N}, + {"KeyO", KEY_O}, + {"KeyP", KEY_P}, + {"KeyQ", KEY_Q}, + {"KeyR", KEY_R}, + {"KeyS", KEY_S}, + {"KeyT", KEY_T}, + {"KeyU", KEY_U}, + {"KeyV", KEY_V}, + {"KeyW", KEY_W}, + {"KeyX", KEY_X}, + {"KeyY", KEY_Y}, + {"KeyZ", KEY_Z}, + {"Digit1", KEY_1}, + {"Digit2", KEY_2}, + {"Digit3", KEY_3}, + {"Digit4", KEY_4}, + {"Digit5", KEY_5}, + {"Digit6", KEY_6}, + {"Digit7", KEY_7}, + {"Digit8", KEY_8}, + {"Digit9", KEY_9}, + {"Digit0", KEY_0}, + {"Enter", KEY_ENTER}, + {"Escape", KEY_ESC}, + {"Backspace", KEY_BACKSPACE}, + {"Tab", KEY_TAB}, + {"Space", KEY_SPACE}, + {"Minus", KEY_MINUS}, + {"Equal", KEY_EQUAL}, + {"BracketLeft", KEY_LEFTBRACE}, + {"BracketRight", KEY_RIGHTBRACE}, + {"Backslash", KEY_BACKSLASH}, + {"Semicolon", KEY_SEMICOLON}, + {"Quote", KEY_APOSTROPHE}, + {"Backquote", KEY_GRAVE}, + {"Comma", KEY_COMMA}, + {"Period", KEY_DOT}, + {"Slash", KEY_SLASH}, + {"CapsLock", KEY_CAPSLOCK}, + {"F1", KEY_F1}, + {"F2", KEY_F2}, + {"F3", KEY_F3}, + {"F4", KEY_F4}, + {"F5", KEY_F5}, + {"F6", KEY_F6}, + {"F7", KEY_F7}, + {"F8", KEY_F8}, + {"F9", KEY_F9}, + {"F10", KEY_F10}, + {"F11", KEY_F11}, + {"F12", KEY_F12}, + {"PrintScreen", KEY_SYSRQ}, + {"ScrollLock", KEY_SCROLLLOCK}, + {"Pause", KEY_PAUSE}, + {"Insert", KEY_INSERT}, + {"Home", KEY_HOME}, + {"PageUp", KEY_PAGEUP}, + {"Delete", KEY_DELETE}, + {"End", KEY_END}, + {"PageDown", KEY_PAGEDOWN}, + {"ArrowRight", KEY_RIGHT}, + {"ArrowLeft", KEY_LEFT}, + {"ArrowDown", KEY_DOWN}, + {"ArrowUp", KEY_UP}, + {"NumLock", KEY_NUMLOCK}, + {"NumpadDivide", KEY_KPSLASH}, + {"NumpadMultiply", KEY_KPASTERISK}, + {"NumpadSubtract", KEY_KPMINUS}, + {"NumpadAdd", KEY_KPPLUS}, + {"NumpadEnter", KEY_KPENTER}, + {"Numpad1", KEY_KP1}, + {"Numpad2", KEY_KP2}, + {"Numpad3", KEY_KP3}, + {"Numpad4", KEY_KP4}, + {"Numpad5", KEY_KP5}, + {"Numpad6", KEY_KP6}, + {"Numpad7", KEY_KP7}, + {"Numpad8", KEY_KP8}, + {"Numpad9", KEY_KP9}, + {"Numpad0", KEY_KP0}, + {"NumpadDecimal", KEY_KPDOT}, + {"WakeUp", KEY_POWER} +}; + +static keycode_dict modtable[] = { + {"ControlLeft", KEY_MOD_LCTRL}, + {"ShiftLeft", KEY_MOD_LSHIFT}, + {"AltLeft", KEY_MOD_LALT}, + {"MetaLeft", KEY_MOD_LMETA}, + {"ControlRight", KEY_MOD_RCTRL}, + {"ShiftRight", KEY_MOD_RSHIFT}, + {"AltRight", KEY_MOD_RALT}, + {"MetaRight", KEY_MOD_RMETA} +}; + +#define NKEYS ( sizeof(keytable)/sizeof(keycode_dict) ) +#define NMODS ( sizeof(modtable)/sizeof(keycode_dict) ) + +#endif diff --git a/server.c b/server.c new file mode 100644 index 0000000..a264bb1 --- /dev/null +++ b/server.c @@ -0,0 +1,388 @@ +#include +#include + +#include "pico/stdlib.h" +#include "lwip/apps/httpd.h" +#include "lwip/ip4_addr.h" +#include "pico/cyw43_arch.h" +#include "hardware/watchdog.h" +#include "hardware/flash.h" +#include "hardware/sync.h" +#include "pico/multicore.h" + +#include "server.h" +#include "parse_keys.h" +#include "dhcpserver.h" + +uint8_t led_code = 0; +static uint8_t ip[4]; +static uint8_t mask[4]; +static uint8_t gw[4]; +static absolute_time_t lastCheck; +static absolute_time_t lastActive; +static net_config wifi; +static bool clientmode = false; +static bool config_loaded = false; +static bool bad_config = false; +static bool reboot = false; + +const char * __not_in_flash("httpd") ssi_tags[] = { + "num", + "caps", + "scroll", + "ssid", + "pass", + "host", + "ip0", + "ip1", + "ip2", + "ip3", + "mask0", + "mask1", + "mask2", + "mask3", + "gw0", + "gw1", + "gw2", + "gw3", + "dhcp" +}; + + +static const tCGI cgi_handlers[] = { + { "/sendkeys.cgi", sendkeys_cgi }, + { "/wifi.cgi", save_wifi }, + { "/reboot.cgi", reboot_cgi }, +}; + +void run_http_server() { + //sleep_ms(5000); + + if (cyw43_arch_init_with_country(CYW43_COUNTRY_USA)) { + printf("failed to initialize\n"); + return; + } + + clientmode = false; + + config_loaded = net_config_load(&wifi); + + if ( config_loaded ){ + printf("read config file\n"); + cyw43_arch_enable_sta_mode(); + + // set hostname + //cyw43_arch_lwip_begin(); + struct netif *n = &cyw43_state.netif[CYW43_ITF_STA]; + if (wifi.host) { + netif_set_hostname(n, wifi.host); + } else { + netif_set_hostname(n, DEFAULTHOST); + } + if (wifi.manual) { + dhcp_release_and_stop(n); + netif_set_addr(n, &(wifi.ip), &(wifi.mask), &(wifi.gw)); + dhcp_inform(n); + } + netif_set_up(n); + //cyw43_arch_lwip_end(); + + if(cyw43_arch_wifi_connect_timeout_ms(wifi.ssid, wifi.pass, CYW43_AUTH_WPA2_AES_PSK, 10000)){ + printf("failed to connect to %s\n", wifi.ssid); + } else{ + clientmode = true; + } + } + + if (!clientmode) { + //start AP mode + cyw43_arch_enable_ap_mode(DEFAULTHOST, DEFAULTPASS, CYW43_AUTH_WPA2_AES_PSK); + + ip4_addr_t ip, mask, gw; + IP4_ADDR(&ip, 192, 168, 0, 1); + IP4_ADDR(&mask, 255, 255, 255, 0); + IP4_ADDR(&gw, 192, 168, 0, 1); + netif_set_ipaddr(netif_default, &ip); + netif_set_up(netif_default); + + dhcp_server_t dhcp; + dhcp_server_init(&dhcp, &gw, &mask); + printf("launched in AP mode\n"); + } + + // start the server + httpd_init(); + http_set_cgi_handlers(cgi_handlers, 3); + for (size_t i = 0; i < LWIP_ARRAYSIZE(ssi_tags); i++) { + LWIP_ASSERT("tag too long for LWIP_HTTPD_MAX_TAG_NAME_LEN", + strlen(ssi_tags[i]) <= LWIP_HTTPD_MAX_TAG_NAME_LEN); + } + http_set_ssi_handler(ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags)); + printf("HTTP server initialized\n"); + + watchdog_enable(8000,1); + + if (clientmode) { + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN,1); + while(true) { + if ( absolute_time_diff_us(lastCheck, get_absolute_time()) > 5000000) { + if ( cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) == 3 ) { + lastCheck = get_absolute_time(); + if(!reboot){ + watchdog_update(); + } + } + } + } + } else { + lastActive = get_absolute_time(); //initialize activity timer + static int led = 1; + while(true) { + if (absolute_time_diff_us(lastCheck, get_absolute_time()) > 1000000) { + led = !led; + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led); + lastCheck = get_absolute_time(); + if ( config_loaded && (absolute_time_diff_us(lastActive, lastCheck) > 600000000)) { + reboot = true; + } + if(!reboot) { + watchdog_update(); + } + } + } + } +} + +const char * sendkeys_cgi (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { + for (int i=0; i < iNumParams; i++) { + if (strcmp(pcParam[i], "keys") == 0 ) { + //printf("Web input: %s\n", pcValue[i]); + parse_key_list(pcValue[i]); + } + } + + lastActive= get_absolute_time(); + + // send return page + return "/success.html"; +} + +const char * save_wifi (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { + // clear all values in manual network settings + memset(ip, 0, sizeof(ip)); + memset(mask, 0, sizeof(mask)); + memset(gw, 0, sizeof(gw)); + + bad_config = false; + wifi.manual = true; + + for (int i=0; i < iNumParams; i++) { + if (strcmp(pcParam[i], "ssid") == 0){ + if (pcValue[i][0] == "\0") { + bad_config = true; + } else { + urldecode(pcValue[i], wifi.ssid); + } + } else if (strcmp(pcParam[i], "pass") == 0) { + urldecode(pcValue[i], wifi.pass); + } else if (strcmp(pcParam[i], "host") == 0) { + urldecode(pcValue[i], wifi.host); + } else if (strcmp(pcParam[i], "dhcp") == 0) { + wifi.manual = false; + } else if (strncmp(pcParam[i], "ip", 2) ==0 ) { + uint8_t part = atoi(&(pcParam[i][2])); + int val = atoi(pcValue[i]); + if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) { + bad_config = true; + } else { + ip[part] = (uint8_t) val; + } + } else if (strncmp(pcParam[i], "gw", 2) ==0 ) { + uint8_t part = atoi(&(pcParam[i][2])); + int val = atoi(pcValue[i]); + if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) { + bad_config = true; + } else { + gw[part] = (uint8_t) val; + } + } else if (strncmp(pcParam[i], "mask", 4) ==0 ) { + uint8_t part = atoi(&(pcParam[i][4])); + int val = atoi(pcValue[i]); + if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) { + bad_config = true; + } else { + mask[part] = (uint8_t) val; + } + } + } + + if (bad_config) { + return "/wifi.shtml"; + } else { + IP4_ADDR(&(wifi.ip), ip[0], ip[1], ip[2], ip[3]); + if(!wifi.ip.addr) { + wifi.ip.addr = IPADDR_NONE; + } + IP4_ADDR(&(wifi.mask), mask[0], mask[1], mask[2], mask[3]); + if(!wifi.mask.addr) { + wifi.mask.addr = IPADDR_NONE; + } + IP4_ADDR(&(wifi.gw), gw[0], gw[1], gw[2], gw[3]); + if(!wifi.gw.addr) { + wifi.gw.addr = IPADDR_NONE; + } + wifi.header = STARTFILE; + wifi.footer = ENDFILE; + config_loaded = true; + + watchdog_update(); + + net_config_write(&wifi); + + printf("wifi settings saved\n"); + + return "/success.html"; + } +} + +const char * reboot_cgi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { + reboot = true; + + return "/success.html"; +} + + +void net_config_write(net_config *config) { + multicore_lockout_start_blocking(); + + uint8_t buf[FLASH_PAGE_SIZE]; + memset(buf, 0x00, FLASH_PAGE_SIZE); + memcpy(buf, config, sizeof(net_config)); + + uint32_t interrupts = save_and_disable_interrupts(); + flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE); + flash_range_program(FLASH_TARGET_OFFSET, buf, FLASH_PAGE_SIZE); + restore_interrupts(interrupts); + + multicore_lockout_end_blocking(); +} + +bool net_config_load(net_config *config) { + const uint8_t *data = (const uint8_t *) (XIP_BASE+FLASH_TARGET_OFFSET); + memcpy(config, data, sizeof(net_config)); + + return ( (config->header == STARTFILE) && (config->footer == ENDFILE) ); +} + +uint16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen) { + size_t printed; + switch (iIndex) { + case 0: //num + if (led_code & 1) { + printed = snprintf(pcInsert, iInsertLen, "on"); + } else { + printed = snprintf(pcInsert, iInsertLen, "off"); + } + break; + case 1: //caps + if (led_code & 2) { + printed = snprintf(pcInsert, iInsertLen, "on"); + } else { + printed = snprintf(pcInsert, iInsertLen, "off"); + } + break; + case 2: //scroll + if (led_code & 4) { + printed = snprintf(pcInsert, iInsertLen, "on"); + } else { + printed = snprintf(pcInsert, iInsertLen, "off"); + } + break; + case 3: //ssid + if (config_loaded && wifi.ssid) { + printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.ssid); + } else { + printed = 0; + } + break; + case 4: //pass + if (config_loaded && wifi.pass) { + printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.pass); + } else { + printed = 0; + } + break; + case 5: //host + if (config_loaded && wifi.host) { + printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.host); + } else { + printed = 0; + } + break; + case 6: + case 7: + case 8: + case 9: //ip0-3 + if (config_loaded && wifi.ip.addr) { + printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.ip), iIndex-6)); + } else { + printed = 0; + } + break; + case 10: + case 11: + case 12: + case 13: //mask0-3 + if (config_loaded && wifi.mask.addr) { + printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.mask), iIndex-10)); + } else { + printed = 0; + } + break; + case 14: + case 15: + case 16: + case 17: //gw0-3 + if (config_loaded && wifi.gw.addr) { + printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.gw), iIndex-14)); + } else { + printed = 0; + } + break; + case 18: // dhcp + if ((!config_loaded) || !(wifi.manual) ){ + printed = snprintf(pcInsert, iInsertLen, "checked"); + } else { + printed = 0; + } + break; + default: //undefined tag + printed = 0; + break; + } + LWIP_ASSERT("illegal length returned", printed <= 0xFFFF); + return (uint16_t)printed; +} + +void set_indicator(uint8_t const* buffer) { + led_code = *buffer; +} + +void urldecode(char *urlstring, char *decoded) { + uint8_t conv; + while(*urlstring) { + if(*urlstring == '+') { + *decoded=' '; + } else if (*urlstring == '%') { + urlstring++; + sscanf(urlstring, "%02hhx", &conv); + *decoded = conv; + urlstring++; + } else { + *decoded = *urlstring; + } + urlstring++;; + decoded++; + } + *decoded = '\0'; +} diff --git a/server.h b/server.h new file mode 100644 index 0000000..ee051df --- /dev/null +++ b/server.h @@ -0,0 +1,35 @@ +#ifndef SERVER_H_ +#define SERVER_H_ + +#include "lwip/ip4_addr.h" + +#define STARTFILE 0x7fc6 +#define ENDFILE 0x0464 +#define DEFAULTHOST "picokb" +#define DEFAULTPASS "password" + +typedef struct { + uint16_t header; + char ssid[32+1]; + char pass[63+1]; + char host[63+1]; + bool manual; + ip4_addr_t ip; + ip4_addr_t mask; + ip4_addr_t gw; + uint16_t footer; +} net_config; + +void run_http_server(); +const char * sendkeys_cgi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); +const char * save_wifi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); +const char * reboot_cgi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); +uint16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen); +void set_indicator(uint8_t const* buffer); +void urldecode(char *urlstring, char *dest); +bool net_config_load(net_config *wifi); +void net_config_write(net_config *wifi); + +#define FLASH_TARGET_OFFSET ((PICO_FLASH_SIZE_BYTES) - FLASH_SECTOR_SIZE) + +#endif diff --git a/tusb_config.h b/tusb_config.h new file mode 100644 index 0000000..164f0cf --- /dev/null +++ b/tusb_config.h @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +#define CFG_TUSB_OS OPT_OS_PICO + +// Enable device stack +#define CFG_TUD_ENABLED 1 + +// Enable host stack with pio-usb if Pico-PIO-USB library is available +#define CFG_TUH_ENABLED 0 +#define CFG_TUH_RPI_PIO_USB 0 + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//------------- CLASS -------------// +#define CFG_TUD_CDC 1 +#define CFG_TUD_HID 1 + +#define CFG_TUD_CDC_RX_BUFSIZE 64 +#define CFG_TUD_CDC_TX_BUFSIZE 64 + +#define CFG_TUD_HID_EP_BUFSIZE 16 + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/usb_descriptors.c b/usb_descriptors.c new file mode 100644 index 0000000..ae477c5 --- /dev/null +++ b/usb_descriptors.c @@ -0,0 +1,195 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * sekigon-gonnoc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "tusb.h" +#include "usb_descriptors.h" + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) + +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = USB_BCD, + + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) +{ + return (uint8_t const *) &desc_device; +} + + +//--------------------------------------------------------------------+ +// Configuration Descriptor +//--------------------------------------------------------------------+ + +#define EPNUM_CDC_NOTIF 0x81 +#define EPNUM_CDC_OUT 0x02 +#define EPNUM_CDC_IN 0x82 +#define EPNUM_HID 0x83 + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_DESC_LEN) + +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD)) +}; + + + +// full speed configuration +uint8_t const desc_fs_configuration[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), + TUD_HID_DESCRIPTOR(ITF_NUM_HID, 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5), +}; + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + return desc_fs_configuration; +} + + +//--------------------------------------------------------------------+ +// String Descriptors +//--------------------------------------------------------------------+ + +// array of pointer to string descriptors +char const* string_desc_arr [] = +{ + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "Raspberry Pi", // 1: Manufacturer + "Pico Web Keyboard", // 2: Product + "1234567890123456789", // 3: Serials, should use chip ID + "Pico Web Keyboard CDC", // 4: CC Interface + "TinyUSB Keyboard", // 5: HID Keyboard Interface +}; + +static uint16_t _desc_str[32]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + (void) langid; + + uint8_t chr_count; + + if ( index == 0) + { + memcpy(&_desc_str[1], string_desc_arr[0], 2); + chr_count = 1; + }else + { + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; + + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = (uint8_t) strlen(str); + if ( chr_count > 31 ) chr_count = 31; + + // Convert ASCII string into UTF-16 + for(uint8_t i=0; i