diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..301b7bd --- /dev/null +++ b/src/index.html @@ -0,0 +1,157 @@ + + + + + + ESP-Time-Server + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

GNSSTimeServer

+
+

GNSS Time Server v

+

+
________ + ___________________________________________
MCU
+
Uptime:
+
+ Free Heap:

+ Minimum Heap:

+ IDF Version:

+ Internal Temperature:
___________________________________________________
WiFi
+
IP:
+
+ Network:

+ Type:

+ Signal:

+ MAC Address:
___________________________________________________
Sats
+
Timestamp:
+
+ Locked:

+ Latitude:

+ Longitude:

+ Satellites:

+
Precision:
___________________________________________________
RTC
+
Valid Timestamp:
+
+ RTC Running:

+ Aging Offset:

+
RTC Temperature:
___________________________________________________
Config
+
+
Syslog server:
SSID:
Password:
+
___________________________________________________
+


+

+

https://github.com/Montecri/GNSSTimeServer

+

Images Attribution

+ + + diff --git a/src/index_bytearray.h b/src/index_bytearray.h new file mode 100644 index 0000000..a526a00 --- /dev/null +++ b/src/index_bytearray.h @@ -0,0 +1,4 @@ +#define index_gz_len 19559 +const uint8_t index_gz[] PROGMEM = { +0x1F, 0x8B, 0x08, 0x08, 0x3B, 0x75, 0xDE, 0x64, 0x02, 0xFF, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x2E, 0x68, 0x00, 0xEC, 0xBC, 0xD9, 0xCE, 0xF5, 0x48, 0x96, 0x1D, 0x76, 0x6D, 0x01, 0x7A, 0x87, 0xDF, 0x09, 0xF8, 0x8A, 0x2A, 0x71, 0x9E, 0xAA, 0x32, 0x0B, 0xE0, 0x4C, 0x1E, 0xCE, 0x33, 0x0F, 0x6F, 0x04, 0xCE, 0xF3, 0x3C, 0x1D, 0xF2, 0xE9, 0x7D, 0xFE, 0xCC, 0xEA, 0xB6, 0xBA, 0x5A, 0x36, 0xDA, 0x2E, 0xB5, 0x20, 0x03, 0xE2, 0xCD, 0x61, 0x04, 0xC9, 0x1D, 0x11, 0x3B, 0x22, 0xD6, 0x5E, 0x6B, 0x93, 0xDF, 0xF7, 0x6B, 0xBD, 0x0F, 0xFD, 0x5F, 0xFF, 0xE3, 0x7F, 0xF8, 0xF5, 0x7F, 0xE7, 0x4D, 0xCE, 0x7B, 0x5B, 0xC2, 0x8F, 0xBF, 0x55, 0xFC, 0xF8, 0xF1, 0x6B, 0x5D, 0x24, 0xF9, 0xEF, 0x67, 0xDF, 0xF3, 0xA1, 0xD8, 0x93, 0xEF, 0xA5, 0x7D, 0xFE, 0x53, 0xB1, 0x1C, 0xCD, 0xF9, 0xDB, 0x2F, 0xD9, 0x34, 0xEE, 0xC5, 0xB8, 0xFF, 0x69, 0xBF, 0xE7, 0xE2, 0x97, 0x1F, 0x7F, 0x2B, 0xFD, 0xF6, 0xCB, 0x5E, 0x7C, 0x76, 0xF0, 0xA7, 0x89, 0xBF, 0xFC, 0xC8, 0xEA, 0x64, 0xDD, 0x8A, 0xFD, 0x37, 0xDF, 0x13, 0xFF, 0x44, 0xFD, 0xF2, 0x2F, 0x0C, 0x8D, 0xC9, 0x50, 0xFC, 0xF6, 0xCB, 0xD9, 0x14, 0xD7, 0x3C, 0xAD, 0xFB, 0x7F, 0xF5, 0xF8, 0xD5, 0xE4, 0x7B, 0xFD, 0x5B, 0x5E, 0x9C, 0x4D, 0x56, 0xFC, 0xE9, 0xF7, 0xC2, 0x7F, 0xFA, 0xD1, 0x8C, 0xCD, 0xDE, 0x24, 0xFD, 0x9F, 0xB6, 0x2C, 0xE9, 0x8B, 0xDF, 0xE0, 0x7F, 0xB6, 0xB4, 0x37, 0x7B, 0x5F, 0xFC, 0x55, 0x70, 0xAD, 0x3F, 0x79, 0xCD, 0x50, 0xFC, 0xC9, 0x2D, 0xD6, 0xB3, 0x58, 0x7F, 0x05, 0xFF, 0xA8, 0xFE, 0x8F, 0xFF, 0xE1, 0x7F, 0xFB, 0xB5, 0x6F, 0xC6, 0xEE, 0xC7, 0x5A, 0xF4, 0xBF, 0xFD, 0xD2, 0x7C, 0x1B, 0xF8, 0xE5, 0xC7, 0xCF, 0xAE, 0x7E, 0xCF, 0x87, 0xA4, 0x2A, 0xC0, 0x79, 0xAC, 0x7E, 0xF9, 0xB1, 0x35, 0x4F, 0xB1, 0xFD, 0xF6, 0x0B, 0x4C, 0x7C, 0x60, 0xE2, 0x97, 0x1F, 0xF5, 0x5A, 0x94, 0xBF, 0xFD, 0xF2, 0x23, 0x4F, 0xF6, 0xE4, 0xCF, 0xFF, 0x7C, 0xD3, 0x5F, 0xD2, 0x64, 0x2B, 0x08, 0xEC, 0x3F, 0x35, 0x01, 0x6B, 0x3A, 0x17, 0xA4, 0x4A, 0xD5, 0xC4, 0x7C, 0x0F, 0xC3, 0xF5, 0x6B, 0xC1, 0xAF, 0xBE, 0x67, 0xEC, 0xCF, 0x22, 0x63, 0x73, 0xCC, 0xFB, 0xE7, 0x6F, 0x49, 0x81, 0x74, 0xFD, 0x7B, 0x4D, 0x64, 0xB8, 0x0E, 0xA4, 0x30, 0xEB, 0x86, 0x65, 0x84, 0xFD, 0xB3, 0xC2, 0x19, 0x6D, 0x1F, 0xFE, 0xDE, 0xCD, 0x7D, 0xDA, 0xEB, 0xA4, 0xDE, 0xB6, 0xFF, 0xB3, 0xF2, 0x95, 0x09, 0x75, 0x9C, 0x5D, 0x0C, 0xC3, 0x6F, 0x3F, 0x6F, 0x22, 0x05, 0x26, 0xF6, 0x57, 0xBE, 0xDE, 0xBE, 0xE7, 0x5A, 0xE9, 0xFA, 0x0E, 0x1B, 0xF0, 0xB5, 0x15, 0xC4, 0x96, 0x96, 0x7E, 0x1C, 0x59, 0xD0, 0x13, 0xB0, 0xDC, 0x1E, 0xED, 0xB8, 0x55, 0x8D, 0x77, 0x6F, 0xED, 0x1D, 0x9A, 0xD0, 0xC0, 0x32, 0x69, 0x06, 0x09, 0xDC, 0x8B, 0x71, 0x50, 0xDB, 0xB8, 0xF0, 0x30, 0xB8, 0xF1, 0x6A, 0xB6, 0x9F, 0x98, 0xF0, 0xB2, 0x0C, 0xFB, 0x50, 0x77, 0x0D, 0x2B, 0x60, 0xC5, 0x6A, 0x8D, 0x7B, 0xC9, 0xCD, 0xBB, 0x8C, 0x14, 0xC5, 0x15, 0xCF, 0x32, 0x6D, 0x3E, 0xDE, 0xA7, 0x5B, 0x1F, 0x88, 0x34, 0x69, 0xFD, 0x41, 0x93, 0x2E, 0x91, 0x59, 0xA6, 0xA7, 0x4B, 0x4F, 0xA7, 0xAD, 0x62, 0x5D, 0xCF, 0x79, 0x08, 0x07, 0x06, 0x44, 0x55, 0xB8, 0x14, 0x05, 0x44, 0x56, 0x32, 0x5F, 0xC4, 0x81, 0x63, 0x6D, 0xF4, 0xD7, 0x8C, 0x03, 0xA3, 0x77, 0x72, 0xB1, 0x0E, 0xD6, 0xF3, 0x0B, 0xA9, 0x93, 0x78, 0x78, 0xE7, 0x30, 0x07, 0x7A, 0x4B, 0x05, 0xB6, 0xAD, 0x1D, 0x48, 0x07, 0xF5, 0x0E, 0x2A, 0x2F, 0xCA, 0x3D, 0xED, 0x64, 0xC7, 0x34, 0xB4, 0xB6, 0x7A, 0xE8, 0xE0, 0x01, 0x88, 0xDF, 0x96, 0xFF, 0xA1, 0x4F, 0xF8, 0xB2, 0xB6, 0xED, 0x83, 0x93, 0x34, 0x66, 0x9D, 0x71, 0x64, 0x1E, 0xFB, 0x43, 0xD1, 0x42, 0xD3, 0x21, 0xCE, 0x95, 0xF5, 0x4D, 0xFF, 0xD2, 0xB6, 0x25, 0x67, 0x93, 0x38, 0x7F, 0xA5, 0xF3, 0x38, 0xF7, 0x1B, 0xDA, 0x81, 0xD6, 0x98, 0x6C, 0xBA, 0x87, 0x11, 0xAA, 0xA2, 0x1C, 0x8F, 0x50, 0x50, 0x4F, 0x5B, 0x43, 0x53, 0xA0, 0x76, 0x9D, 0xBD, 0x8E, 0x79, 0x4E, 0x9B, 0x1E, 0xBE, 0xEF, 0x79, 0x51, 0xB8, 0x6D, 0x83, 0x8B, 0xB9, 0x0A, 0xF5, 0x29, 0xFA, 0xC0, 0xC4, 0x71, 0xD0, 0x1C, 0xF8, 0x46, 0xDE, 0x43, 0x0A, 0xC0, 0xC5, 0x19, 0xD9, 0xD7, 0xD8, 0x56, 0x35, 0xA9, 0x57, 0xCA, 0xC4, 0x0D, 0xA7, 0xBF, 0x73, 0x00, 0x0F, 0x45, 0x7C, 0x5D, 0xC9, 0xFA, 0x15, 0x2F, 0xD7, 0x44, 0x06, 0x0A, 0x0F, 0xA8, 0x03, 0xA8, 0xD5, 0xBB, 0x13, 0x60, 0x54, 0x47, 0x7B, 0x8F, 0xE3, 0xE2, 0xA4, 0xCD, 0x9F, 0x67, 0xAB, 0xC0, 0xCD, 0x9A, 0x97, 0xBC, 0xB7, 0x52, 0x56, 0x72, 0xC3, 0x14, 0x33, 0x76, 0x18, 0x4E, 0x62, 0xFA, 0x43, 0x19, 0xD7, 0xC9, 0x48, 0x47, 0x57, 0x8F, 0x88, 0x8B, 0xBF, 0xEA, 0x80, 0x6C, 0xC7, 0x5E, 0x5F, 0x90, 0x71, 0x4B, 0xC6, 0x07, 0x07, 0x3F, 0xEF, 0xA5, 0xCF, 0x9F, 0xF9, 0xEA, 0x1E, 0xD4, 0xD8, 0xD2, 0x10, 0xA6, 0x4B, 0x97, 0xF0, 0xBA, 0xD7, 0x3B, 0x36, 0xFA, 0x8D, 0xC8, 0xE6, 0xCD, 0xF8, 0x1A, 0xE1, 0x75, 0xDD, 0x9B, 0x7D, 0x22, 0xB3, 0x1D, 0x57, 0x4E, 0x52, 0x7F, 0x75, 0xC9, 0x50, 0x5D, 0x21, 0x4A, 0xBE, 0x6F, 0x3C, 0x57, 0xD8, 0x6E, 0x9C, 0xD9, 0x2B, 0x5F, 0x87, 0x50, 0x0C, 0xCD, 0x05, 0x06, 0xDE, 0x6B, 0x19, 0xEB, 0x92, 0xAE, 0x2F, 0xBB, 0xBF, 0x94, 0x2D, 0xFE, 0xB0, 0x13, 0x9C, 0xF0, 0x85, 0x5A, 0x3A, 0x51, 0x0B, 0x5A, 0x5B, 0x68, 0xD1, 0x89, 0x8E, 0xF9, 0x2D, 0xC5, 0xA9, 0x6E, 0x78, 0x6B, 0xDC, 0x69, 0xC4, 0xEF, 0x38, 0x4E, 0x62, 0x24, 0xC0, 0xCD, 0x34, 0x12, 0x04, 0xB5, 0xB2, 0x9B, 0x04, 0x79, 0x35, 0xF9, 0x67, 0x91, 0x7D, 0x17, 0x8E, 0xF5, 0xBD, 0x65, 0x89, 0xB2, 0xB2, 0x52, 0xAA, 0xCC, 0x02, 0x40, 0xD0, 0xCD, 0xAD, 0xD6, 0xFB, 0xB2, 0x08, 0xC7, 0x85, 0xEF, 0xED, 0x65, 0x0E, 0x65, 0xB0, 0x26, 0xDE, 0xB7, 0xEE, 0xE9, 0x86, 0xE9, 0x99, 0xA2, 0xA1, 0xB2, 0x56, 0x58, 0xB5, 0x1D, 0xAB, 0x49, 0xD2, 0x9E, 0x5D, 0x97, 0x8A, 0x40, 0x54, 0x68, 0x68, 0x39, 0xDA, 0xF3, 0x12, 0x8A, 0x4E, 0x5B, 0x75, 0x4F, 0xB5, 0x51, 0x3E, 0xB6, 0x0D, 0xA1, 0x4F, 0x5A, 0xA9, 0x1F, 0xD1, 0xB3, 0xF9, 0x55, 0x0A, 0xA5, 0x30, 0xEE, 0xC6, 0x3B, 0xFD, 0x10, 0x1B, 0xB9, 0x1E, 0x2B, 0x02, 0x61, 0xB1, 0x94, 0x94, 0x60, 0x9D, 0x52, 0xEA, 0x95, 0x7E, 0x97, 0xB5, 0xAA, 0xB9, 0x7C, 0x6B, 0x93, 0xD7, 0x13, 0x0A, 0xBB, 0x51, 0x07, 0xC3, 0x7B, 0x88, 0xDC, 0x0A, 0x29, 0x26, 0x80, 0xFB, 0x24, 0x65, 0x8A, 0xEE, 0x93, 0x14, 0xBD, 0x66, 0xA7, 0x84, 0x69, 0xFD, 0x9D, 0x19, 0x58, 0xC6, 0xD5, 0x0B, 0xD2, 0xEA, 0x31, 0xA8, 0x63, 0x52, 0x28, 0x9C, 0xFA, 0x1B, 0x49, 0x03, 0x34, 0x4F, 0x70, 0x56, 0x08, 0x81, 0xA5, 0x5C, 0xC8, 0x37, 0xBA, 0xD8, 0x86, 0x3E, 0xEC, 0x1B, 0x53, 0x71, 0xEF, 0x64, 0x10, 0xD1, 0x14, 0x7A, 0xD7, 0xB5, 0x22, 0xC4, 0xAF, 0x68, 0x23, 0x6F, 0x11, 0xA3, 0xE8, 0x58, 0x2C, 0x6F, 0xFA, 0x68, 0x88, 0x20, 0xE2, 0x29, 0xF8, 0x00, 0x9F, 0xC2, 0x1B, 0xE8, 0xE8, 0xDE, 0xB4, 0x1B, 0x2C, 0xFB, 0x6D, 0x9D, 0x93, 0x12, 0x72, 0xA5, 0x20, 0x6C, 0xDB, 0xFC, 0x10, 0x55, 0xE4, 0x15, 0x8F, 0xE4, 0x46, 0xC8, 0x85, 0xEC, 0xA6, 0xE0, 0xCA, 0xE7, 0x91, 0x9A, 0x6C, 0x39, 0x62, 0x7C, 0xC0, 0xB1, 0x42, 0x9B, 0x43, 0xB5, 0xB4, 0x1E, 0x98, 0x01, 0x10, 0x27, 0x42, 0xE6, 0x0D, 0x5A, 0xC9, 0x2A, 0xBE, 0x38, 0x39, 0x88, 0x93, 0x08, 0x77, 0xEA, 0x42, 0x08, 0x7C, 0x67, 0xC5, 0xC8, 0xA7, 0xC1, 0x8A, 0xDD, 0x84, 0x2F, 0x53, 0x00, 0x2B, 0x7B, 0x90, 0x34, 0x1E, 0x43, 0x40, 0xFC, 0xA8, 0x30, 0x06, 0xA4, 0x58, 0xB4, 0x2E, 0xD8, 0xC3, 0xAA, 0x63, 0x4E, 0xBB, 0x7E, 0x87, 0x09, 0xD7, 0x0F, 0x4C, 0x47, 0xC5, 0xB9, 0xB7, 0xA2, 0xFC, 0xF6, 0x0B, 0xF8, 0x07, 0xEE, 0x82, 0xFF, 0x0C, 0xBC, 0xBF, 0xA6, 0x53, 0x7E, 0xFF, 0x33, 0xDE, 0x25, 0x69, 0x5F, 0xFC, 0xD8, 0xF6, 0xFB, 0x8B, 0x82, 0x7F, 0x00, 0xE5, 0x9F, 0x7F, 0xC0, 0x10, 0xF4, 0x7F, 0xFC, 0xE5, 0x47, 0x5D, 0x34, 0x55, 0xBD, 0xFF, 0xF9, 0x07, 0x4E, 0x92, 0xF3, 0xE7, 0x2F, 0x5F, 0x38, 0x2D, 0xFA, 0x7E, 0x4E, 0xF2, 0xBC, 0x19, 0xAB, 0xDF, 0x7E, 0xC1, 0x7E, 0xF9, 0x91, 0x4E, 0x6B, 0x5E, 0xAC, 0xBF, 0xFD, 0x02, 0xFD, 0x13, 0x76, 0xFE, 0xB4, 0xF6, 0x5F, 0x99, 0xFE, 0xA3, 0x62, 0xFD, 0xAF, 0x4A, 0x3F, 0xCB, 0xF9, 0x3F, 0xB5, 0xF5, 0x85, 0xD5, 0xBD, 0xF9, 0x82, 0xEF, 0x9F, 0x92, 0xBE, 0xA9, 0xC6, 0x3F, 0xFF, 0x18, 0x9A, 0x3C, 0xEF, 0x8B, 0xBF, 0xFC, 0x48, 0x93, 0xAC, 0xAB, 0xD6, 0xE9, 0x18, 0xF3, 0x3F, 0x65, 0x53, 0x3F, 0xAD, 0x7F, 0xFE, 0x71, 0xD5, 0xCD, 0x5E, 0xFC, 0xE5, 0x97, 0x7F, 0x61, 0xE8, 0x67, 0x20, 0x81, 0xFF, 0xFA, 0x6B, 0x33, 0x54, 0x3F, 0xB6, 0x35, 0xFB, 0xED, 0x97, 0xFF, 0x97, 0xF8, 0x2A, 0x30, 0xBF, 0x83, 0xEC, 0x1F, 0xF8, 0xCA, 0x2D, 0x49, 0x24, 0x17, 0xBF, 0xD7, 0xC8, 0x06, 0xE7, 0x06, 0xB6, 0xC2, 0x31, 0x95, 0x52, 0x32, 0x75, 0xD7, 0xFC, 0xEE, 0xCD, 0xFE, 0x72, 0xC5, 0xFE, 0xF9, 0x79, 0x19, 0xF9, 0x59, 0xCC, 0x2B, 0x16, 0xE8, 0xEF, 0x21, 0xFB, 0x1D, 0xA7, 0x7B, 0xC8, 0x09, 0x6A, 0xC8, 0x47, 0xE8, 0x21, 0x97, 0xF3, 0x3A, 0x1B, 0x7C, 0x26, 0x47, 0x73, 0x54, 0x1B, 0xFA, 0x23, 0x41, 0x8D, 0xF6, 0x1D, 0xB1, 0xBD, 0x36, 0xD0, 0x77, 0x8C, 0x9F, 0x87, 0xC5, 0xFE, 0xEC, 0x03, 0xBD, 0xFF, 0x8E, 0xBF, 0x72, 0x93, 0x3D, 0xF1, 0x8E, 0x8F, 0xA2, 0x17, 0xF4, 0x59, 0x01, 0xD2, 0x24, 0x1C, 0x45, 0x01, 0x9C, 0x9F, 0xB9, 0x01, 0x31, 0xB7, 0xA6, 0x4E, 0xAB, 0xAA, 0x34, 0x4A, 0x65, 0x8B, 0x6E, 0xD4, 0xAA, 0xD2, 0x04, 0x99, 0x87, 0x5E, 0x35, 0x98, 0x57, 0xD5, 0xDD, 0xBB, 0x5B, 0x54, 0x53, 0xB8, 0xB3, 0x0F, 0x45, 0x72, 0x9E, 0xF0, 0xCE, 0x39, 0xEC, 0xE5, 0xDA, 0xAC, 0xEF, 0xD4, 0x4C, 0x24, 0xF3, 0x83, 0x0E, 0xE8, 0x92, 0xD0, 0xDF, 0xCD, 0xAB, 0x59, 0xD4, 0x43, 0x95, 0x94, 0x54, 0x78, 0x09, 0x84, 0x9A, 0x44, 0xC4, 0x31, 0x47, 0x2B, 0x4C, 0xD0, 0x39, 0x00, 0xE4, 0x16, 0x3E, 0x1F, 0xC7, 0x9C, 0x16, 0x4B, 0x7D, 0xC2, 0x34, 0x38, 0x42, 0x38, 0x6D, 0xC0, 0xE4, 0x98, 0x1E, 0x47, 0x59, 0x14, 0x05, 0x45, 0xE0, 0xF8, 0x35, 0x98, 0x7A, 0xE9, 0x42, 0x23, 0x5C, 0x54, 0xA0, 0xDD, 0x29, 0xBA, 0xA3, 0x41, 0x77, 0x58, 0x9B, 0x6C, 0xB7, 0xB0, 0x4A, 0xC3, 0x83, 0xAE, 0x16, 0x48, 0x0A, 0xA3, 0xF9, 0xCA, 0x5E, 0xB1, 0xEF, 0xAA, 0x98, 0x5A, 0x92, 0x87, 0x24, 0x44, 0x83, 0xCB, 0x20, 0x92, 0xBB, 0x96, 0xFE, 0x68, 0xFC, 0x1A, 0xF8, 0x9F, 0x44, 0x67, 0x3D, 0x3F, 0xB7, 0xE1, 0x5B, 0x80, 0x37, 0x93, 0x84, 0x3E, 0xD1, 0xA5, 0xBE, 0xD5, 0x48, 0xD0, 0xE3, 0x64, 0x8B, 0x52, 0xA7, 0x9F, 0xC9, 0x66, 0x73, 0x3A, 0xFA, 0x55, 0xF1, 0xF4, 0x05, 0x76, 0x22, 0xAE, 0x0C, 0xA9, 0x60, 0x4D, 0x92, 0xA1, 0x96, 0x50, 0xA0, 0x51, 0xF3, 0x84, 0x7C, 0xE4, 0xC6, 0x8C, 0xDE, 0x1A, 0x6B, 0x59, 0xDA, 0x44, 0x22, 0x8E, 0x02, 0xE6, 0xE2, 0xC4, 0x15, 0xE7, 0xC2, 0x08, 0x73, 0x41, 0x0B, 0x04, 0xBC, 0xD9, 0xA2, 0x95, 0x09, 0x3E, 0x0E, 0x33, 0xF2, 0xBB, 0xEA, 0x71, 0x6D, 0x01, 0x05, 0x77, 0x2B, 0x57, 0x93, 0x36, 0x1D, 0xB8, 0xD3, 0x6C, 0xC5, 0xA8, 0xEE, 0x1E, 0x02, 0xED, 0xA9, 0x26, 0xAB, 0x52, 0x3B, 0x74, 0x43, 0x30, 0x60, 0x55, 0x83, 0xB5, 0x4F, 0x17, 0x82, 0x0B, 0x32, 0xAD, 0xA2, 0xF7, 0x0D, 0x08, 0x5C, 0xC0, 0x58, 0xAE, 0x7F, 0x5C, 0xEF, 0xF6, 0xC3, 0xCE, 0x55, 0x29, 0x95, 0xE9, 0x6D, 0xBC, 0x9A, 0xD3, 0xD4, 0x17, 0x4A, 0x3F, 0x35, 0x4A, 0xDF, 0x55, 0x28, 0x13, 0x18, 0x73, 0x6E, 0xBD, 0x8F, 0xE2, 0xA6, 0xB6, 0x56, 0x15, 0xF0, 0x21, 0x26, 0xAB, 0xBA, 0xF2, 0xAC, 0x86, 0x11, 0xB5, 0x38, 0xA6, 0xF3, 0x3B, 0xA2, 0x55, 0x58, 0x33, 0x04, 0xF3, 0x3C, 0x10, 0xDA, 0x84, 0x87, 0xD0, 0xAE, 0x19, 0x1E, 0xED, 0xD7, 0xAD, 0xAB, 0xFA, 0x31, 0x84, 0xD0, 0x34, 0x98, 0xB1, 0x0A, 0x2B, 0xAB, 0xD6, 0x20, 0x58, 0x93, 0x7C, 0x55, 0x38, 0xD7, 0x3B, 0x01, 0x94, 0x7C, 0x88, 0x7B, 0x7F, 0x91, 0x75, 0xCB, 0x13, 0xD2, 0x8E, 0x5C, 0x35, 0x70, 0xD4, 0x7A, 0x1D, 0xDB, 0xD9, 0xEE, 0x30, 0x46, 0x82, 0xDE, 0x6A, 0x11, 0x9E, 0x1F, 0x2C, 0xA0, 0xD2, 0x79, 0x67, 0x18, 0x88, 0x53, 0x53, 0xF3, 0xFC, 0x1C, 0xD8, 0x41, 0xC2, 0xC4, 0xB6, 0x36, 0xF6, 0xA7, 0x3A, 0xCD, 0x57, 0x1B, 0x03, 0x06, 0xB7, 0x64, 0x30, 0x42, 0x94, 0x35, 0x72, 0xAE, 0x0C, 0x57, 0xAD, 0x5A, 0x38, 0xA0, 0xE3, 0x2E, 0x4E, 0x1D, 0x58, 0x22, 0x2C, 0xE0, 0x82, 0x20, 0x5B, 0xEA, 0xAE, 0x52, 0x10, 0x24, 0x22, 0x49, 0xF8, 0x8E, 0x16, 0x88, 0x6B, 0x39, 0xAA, 0x2D, 0x4F, 0x2E, 0xF0, 0x96, 0x54, 0x7B, 0xD9, 0x19, 0x35, 0x81, 0x03, 0x3F, 0x0B, 0x6A, 0x69, 0xC0, 0x40, 0xE6, 0xD5, 0x7C, 0x01, 0x8D, 0x09, 0x91, 0x78, 0x3C, 0x8E, 0x28, 0x2C, 0x09, 0x48, 0x50, 0xCA, 0x36, 0xBF, 0xC6, 0xB8, 0x2F, 0x66, 0x27, 0x8E, 0x70, 0x0D, 0x85, 0xEB, 0xB7, 0x3A, 0xA2, 0x94, 0xA8, 0x20, 0x0B, 0x7A, 0x91, 0x3C, 0x96, 0x42, 0x6A, 0x2D, 0x85, 0xAF, 0x3E, 0x4E, 0xEF, 0xD6, 0x5A, 0x10, 0x53, 0x3D, 0xDA, 0x78, 0xBB, 0x74, 0xA8, 0x7E, 0x61, 0xAC, 0xB6, 0x9D, 0x7A, 0x9F, 0x31, 0x00, 0x78, 0x5F, 0x89, 0xB6, 0x52, 0x8C, 0x68, 0xCF, 0x30, 0x2C, 0x42, 0x2E, 0x29, 0x36, 0x32, 0xC8, 0x45, 0xCF, 0x7B, 0x1E, 0xDF, 0xC2, 0x77, 0x05, 0x4B, 0x9E, 0xE9, 0x5E, 0x43, 0x5E, 0xBE, 0xCE, 0x47, 0x8A, 0x77, 0x86, 0x60, 0x20, 0x90, 0x50, 0xEB, 0x8B, 0x74, 0x28, 0xA0, 0x28, 0xE3, 0xE0, 0xBD, 0x6F, 0x9F, 0x75, 0x85, 0x80, 0x16, 0xB5, 0x85, 0xD1, 0x7B, 0x92, 0x97, 0xB8, 0x00, 0x4D, 0x9B, 0x0D, 0x6B, 0xD5, 0x32, 0xB0, 0x85, 0xF7, 0x2C, 0x98, 0x87, 0x51, 0x1E, 0x8D, 0x37, 0xFA, 0x96, 0x55, 0x0E, 0x16, 0x40, 0xDA, 0x53, 0xCC, 0x07, 0x84, 0x3E, 0x5B, 0xCB, 0x80, 0xD9, 0xED, 0xD7, 0x5A, 0x93, 0xBB, 0xD4, 0xE4, 0x16, 0x96, 0x36, 0xE6, 0x64, 0xDE, 0x1C, 0x0C, 0xCF, 0x48, 0xE8, 0x94, 0x0F, 0xC9, 0xF2, 0x6E, 0x48, 0xB0, 0x01, 0x02, 0x0B, 0xA6, 0xF8, 0x53, 0xF4, 0x3C, 0x00, 0xEB, 0x10, 0xBC, 0xC7, 0x44, 0xA6, 0x71, 0x4E, 0x77, 0x6C, 0xF8, 0x1A, 0xD6, 0xE9, 0xB7, 0x5A, 0x62, 0x56, 0x74, 0x42, 0xD4, 0x9B, 0x01, 0x9A, 0x55, 0x17, 0x3E, 0x05, 0x7C, 0x43, 0x46, 0xCA, 0x46, 0xEB, 0x12, 0x05, 0x06, 0x63, 0xBD, 0xFA, 0x0F, 0x26, 0x89, 0xFC, 0xA2, 0xF5, 0x1F, 0xB5, 0x9D, 0x50, 0x84, 0x0D, 0x00, 0x08, 0xE4, 0xDD, 0x04, 0xA1, 0x2A, 0x41, 0xBC, 0x20, 0x2A, 0xFF, 0x1C, 0xB4, 0x6B, 0x35, 0x59, 0x34, 0xED, 0x05, 0xAE, 0x55, 0x74, 0x8F, 0xC4, 0x4D, 0x1B, 0x24, 0xDE, 0x47, 0xB4, 0xD0, 0x74, 0x3B, 0xDE, 0xF4, 0xA1, 0x6B, 0x6E, 0x6A, 0x59, 0x57, 0xE8, 0xD1, 0x4F, 0xBB, 0xAC, 0x9A, 0xC7, 0x58, 0xA1, 0x5F, 0x19, 0x91, 0x31, 0x4C, 0x0B, 0x64, 0xC2, 0x59, 0x86, 0x72, 0x87, 0x88, 0xD3, 0xE2, 0x72, 0x37, 0x07, 0x67, 0x9E, 0x4E, 0xA7, 0x36, 0x85, 0x92, 0xC6, 0x58, 0x0D, 0x37, 0xE8, 0x37, 0x20, 0x2D, 0x7E, 0xCE, 0x04, 0x70, 0x9C, 0x84, 0xFC, 0xCD, 0xB1, 0xDD, 0x30, 0x7E, 0x69, 0x8C, 0x29, 0xCD, 0xC7, 0x78, 0x4A, 0xF9, 0xF0, 0xDC, 0x0C, 0x5F, 0xB9, 0xD3, 0x11, 0x75, 0xDF, 0xF1, 0xB2, 0x80, 0x64, 0x4F, 0xF3, 0x25, 0x7A, 0x5A, 0xFE, 0x7E, 0x8B, 0x1E, 0x9D, 0xB1, 0x08, 0x62, 0x3E, 0xDF, 0x20, 0x32, 0xC7, 0x6C, 0x64, 0x4E, 0x60, 0x22, 0x2D, 0x2E, 0x1A, 0x22, 0x68, 0xE6, 0x98, 0x6D, 0xAE, 0x3C, 0xC5, 0x33, 0x2F, 0xCA, 0xEB, 0x9A, 0x0F, 0xED, 0x19, 0xA2, 0x35, 0xDA, 0x93, 0x51, 0x78, 0x31, 0xF2, 0x74, 0x7B, 0xD4, 0xCA, 0x1C, 0xF8, 0x2B, 0xB9, 0x27, 0x61, 0xCF, 0xF3, 0xB2, 0x2D, 0x1E, 0xD8, 0x2B, 0x3B, 0x02, 0xF1, 0xCD, 0x50, 0xEC, 0x05, 0x92, 0xC0, 0xA9, 0x6A, 0x42, 0x95, 0x00, 0x24, 0x7A, 0xD0, 0xD4, 0x80, 0xCA, 0x70, 0x03, 0x9C, 0xC5, 0x5B, 0x22, 0x6F, 0x78, 0x43, 0xD3, 0x2C, 0x4B, 0x7E, 0x6F, 0x64, 0x2E, 0xF3, 0x12, 0x13, 0x07, 0x2E, 0x69, 0x7D, 0x77, 0x32, 0x2F, 0xCB, 0x77, 0x4C, 0xAE, 0xF2, 0xF4, 0x26, 0x53, 0xA6, 0xF9, 0x90, 0x38, 0xE2, 0x2C, 0x49, 0xA3, 0x5B, 0x3C, 0x72, 0x1A, 0x89, 0x28, 0x7A, 0x02, 0x7C, 0xAC, 0xF9, 0xCC, 0xFB, 0x84, 0x3B, 0xB0, 0xA9, 0x72, 0x8D, 0xC4, 0x42, 0xE2, 0x84, 0xC8, 0x1D, 0xE1, 0x40, 0x7F, 0x21, 0x0D, 0xA3, 0x43, 0x10, 0xBC, 0xCD, 0x8C, 0xCC, 0x71, 0x21, 0xE2, 0x5A, 0x71, 0x84, 0xAB, 0x8F, 0xC4, 0x3B, 0x60, 0xA2, 0x93, 0xD6, 0xF4, 0xAA, 0x1E, 0x79, 0x4A, 0xB4, 0x7B, 0x8A, 0x5C, 0xCD, 0x0F, 0x0C, 0x4B, 0xE5, 0xA5, 0x0B, 0x79, 0x43, 0xC0, 0x51, 0x99, 0xDD, 0x39, 0x27, 0xFE, 0x6D, 0x1B, 0x82, 0x06, 0xF6, 0xC0, 0x67, 0xEB, 0x78, 0xD2, 0x40, 0x41, 0xE3, 0x21, 0x4B, 0x24, 0xF2, 0xE0, 0x0F, 0x7B, 0xCB, 0x00, 0x9E, 0xD1, 0xF7, 0x0C, 0x96, 0xE8, 0xFE, 0xF1, 0x32, 0xA0, 0x0A, 0x03, 0xAE, 0x16, 0x72, 0x43, 0xC3, 0x09, 0x3B, 0xE4, 0xDE, 0xFB, 0xC3, 0xB4, 0xF8, 0x0C, 0xCA, 0x75, 0xC8, 0x5C, 0x65, 0x38, 0xE7, 0x61, 0x30, 0xEB, 0xA9, 0xF8, 0x7C, 0x56, 0x1B, 0xFF, 0xC6, 0x88, 0x59, 0x4D, 0xE4, 0xCA, 0x0F, 0x76, 0xC6, 0xDD, 0xA2, 0x7B, 0xF7, 0xC1, 0xE7, 0xFC, 0x6C, 0x48, 0x9C, 0xC1, 0x98, 0x47, 0xA9, 0x85, 0xCE, 0xC6, 0x71, 0xB7, 0x09, 0x5A, 0x50, 0x68, 0x12, 0x3E, 0x52, 0xC6, 0x17, 0x27, 0xF6, 0x18, 0xC8, 0x87, 0x66, 0x87, 0xE0, 0xB1, 0x05, 0x8E, 0x28, 0x2B, 0x86, 0x8D, 0xE3, 0x4A, 0x04, 0x21, 0xA8, 0xBE, 0xE7, 0x0F, 0xC8, 0x41, 0xBE, 0x61, 0x2F, 0x89, 0x45, 0x3A, 0x7D, 0x90, 0x97, 0x65, 0x4D, 0xA2, 0x13, 0xEA, 0xEF, 0xA9, 0xA8, 0x2E, 0xFC, 0x8D, 0x98, 0x45, 0xDE, 0x07, 0x58, 0x25, 0xA9, 0xC3, 0x88, 0xB6, 0x9D, 0x39, 0x8C, 0x05, 0x13, 0xF4, 0x45, 0x67, 0xA4, 0xB1, 0xFE, 0x3E, 0x0C, 0x39, 0x7F, 0x5A, 0xA5, 0x11, 0x0D, 0x13, 0x3B, 0x30, 0x12, 0xEF, 0x5F, 0xC9, 0xC8, 0x3D, 0x73, 0x00, 0x7E, 0x59, 0x4B, 0x45, 0x1D, 0x11, 0x34, 0x72, 0x2E, 0xE2, 0x89, 0xA5, 0x6A, 0xEC, 0x14, 0xC0, 0xDF, 0x7D, 0xFE, 0x29, 0x8E, 0x98, 0x1F, 0x0D, 0x12, 0x49, 0x02, 0x87, 0xFA, 0x46, 0xA8, 0xBE, 0x85, 0xA4, 0x64, 0x70, 0x3C, 0xF7, 0xA8, 0xA4, 0x37, 0xCB, 0x99, 0x96, 0x0B, 0x4B, 0x2F, 0xF4, 0xA3, 0xF7, 0x3B, 0x9A, 0xE4, 0x33, 0x61, 0x00, 0x28, 0x0F, 0xD2, 0x00, 0x02, 0x3F, 0x44, 0xE0, 0x3A, 0xF2, 0x67, 0x27, 0xC1, 0x82, 0xDD, 0x34, 0x19, 0x9C, 0x78, 0x3E, 0x97, 0xA5, 0xB5, 0x15, 0xF7, 0x0F, 0xDC, 0x40, 0x31, 0x37, 0x9E, 0x65, 0x59, 0x7D, 0x60, 0x2F, 0x80, 0x2D, 0x2B, 0xDA, 0xB8, 0xCF, 0x85, 0xF5, 0x22, 0x0C, 0x45, 0x6C, 0x28, 0x64, 0xEF, 0xCC, 0xBA, 0x03, 0x07, 0x52, 0xDF, 0x5C, 0xBD, 0xE2, 0x63, 0x69, 0xD1, 0x16, 0x92, 0x43, 0x31, 0xA2, 0xA5, 0x7C, 0x7A, 0xC0, 0xD9, 0x2B, 0xA7, 0xA9, 0x4F, 0x4F, 0x48, 0x3C, 0x7B, 0x47, 0x4E, 0x8E, 0x02, 0x78, 0x4B, 0x4D, 0xB2, 0x7C, 0xC4, 0x36, 0x5D, 0x88, 0x26, 0xED, 0x18, 0x8F, 0xCC, 0xA6, 0x74, 0xD9, 0xF4, 0x24, 0x8D, 0x82, 0x81, 0xBD, 0x1B, 0xC9, 0x44, 0x8D, 0x15, 0x3D, 0xBE, 0x5D, 0x2A, 0xFB, 0x3C, 0xA6, 0x0F, 0x5B, 0x63, 0x0E, 0x5A, 0xB6, 0xBA, 0x7C, 0x06, 0x7F, 0xCD, 0x85, 0x00, 0x45, 0xA9, 0xED, 0x85, 0x17, 0xEE, 0xFD, 0xCE, 0x3E, 0x56, 0xEB, 0x4C, 0xB4, 0x3A, 0xF5, 0x79, 0x00, 0x83, 0xBC, 0xC6, 0xA2, 0xA4, 0x8C, 0x9E, 0x30, 0x98, 0x90, 0x05, 0x8D, 0x3D, 0xD5, 0x16, 0xAE, 0xAA, 0x6E, 0x95, 0x87, 0x4B, 0x40, 0x48, 0x62, 0x2A, 0x72, 0xAB, 0x36, 0x0B, 0xF1, 0x08, 0xD4, 0x83, 0xCD, 0xE3, 0xA8, 0xD4, 0x6C, 0xD3, 0x32, 0xB2, 0xB4, 0x18, 0xB6, 0x1B, 0x06, 0xAA, 0xA0, 0x71, 0xAB, 0x02, 0xAB, 0x35, 0x1F, 0x32, 0x92, 0x66, 0xA6, 0xC6, 0x40, 0x59, 0x99, 0xF7, 0x74, 0x43, 0xE3, 0x10, 0x2F, 0x47, 0x6C, 0x49, 0xA8, 0x78, 0x48, 0x2A, 0x97, 0x7F, 0x6E, 0x46, 0xAC, 0xB9, 0x42, 0xE0, 0xAB, 0x5A, 0xD2, 0x43, 0x03, 0xB3, 0x1E, 0x72, 0x73, 0x20, 0xFD, 0x3C, 0x11, 0x28, 0x99, 0x49, 0x73, 0x4C, 0x6E, 0x2C, 0xF4, 0x0E, 0xBE, 0x36, 0x6C, 0xB0, 0x58, 0xFA, 0xDD, 0x5B, 0xD6, 0x60, 0x6F, 0x7A, 0x02, 0x7D, 0xC7, 0xC0, 0x2B, 0x36, 0x4E, 0x3D, 0xDE, 0x56, 0xE3, 0x36, 0xA7, 0xCB, 0xB3, 0x82, 0xC5, 0xF5, 0xD0, 0x24, 0x65, 0x19, 0xC9, 0xBE, 0x53, 0x86, 0x3D, 0xAE, 0x42, 0x7B, 0x48, 0x0D, 0xB0, 0x27, 0xE0, 0x4B, 0x1E, 0x38, 0x4D, 0xDB, 0x59, 0x3D, 0x56, 0x95, 0xEF, 0x3D, 0xA4, 0x41, 0x7F, 0xFC, 0x54, 0xD8, 0x59, 0x4A, 0x59, 0x89, 0x40, 0xB7, 0xD3, 0xE6, 0x0D, 0xDB, 0x41, 0xCA, 0xCF, 0x78, 0x03, 0xC7, 0x81, 0x67, 0x2F, 0x5F, 0x1F, 0xC0, 0x71, 0x51, 0x4C, 0x38, 0x78, 0x5D, 0x19, 0x8C, 0xAF, 0x47, 0xCB, 0xAE, 0xE1, 0x17, 0x39, 0x52, 0xD1, 0xBE, 0x72, 0x7D, 0x6A, 0xEF, 0x68, 0x09, 0x36, 0xB4, 0x7C, 0xC7, 0xE1, 0x70, 0xF8, 0x81, 0xF0, 0xDD, 0x96, 0x63, 0x3F, 0xDE, 0x57, 0xD9, 0xB1, 0xEE, 0x47, 0x62, 0x23, 0xCD, 0x81, 0xD3, 0x88, 0x42, 0xF0, 0x57, 0x5F, 0x5A, 0xDF, 0x38, 0xDA, 0x3E, 0xD1, 0xCB, 0xCD, 0xD0, 0x86, 0x65, 0x24, 0x1C, 0x83, 0xCA, 0x1B, 0x8C, 0xBC, 0x15, 0x20, 0x9C, 0xDB, 0xB6, 0x3A, 0xD2, 0x02, 0x92, 0xD1, 0x40, 0x49, 0x9F, 0xEA, 0x0C, 0xB1, 0xEE, 0x0A, 0x23, 0x70, 0xEA, 0x7C, 0xDF, 0x40, 0x81, 0xC2, 0x68, 0x02, 0xBA, 0x54, 0x0E, 0x7C, 0xE1, 0x80, 0x21, 0x06, 0x01, 0x0B, 0x2C, 0x76, 0xB7, 0xBE, 0x32, 0xEE, 0x54, 0x70, 0x05, 0x3E, 0x21, 0x74, 0x6F, 0x3B, 0x3A, 0xC4, 0x42, 0x6B, 0xCC, 0xD2, 0x2A, 0xC2, 0x61, 0x39, 0xFF, 0x90, 0x6C, 0xF3, 0xD5, 0x7F, 0x15, 0x60, 0x40, 0x77, 0x09, 0x0D, 0xA6, 0xC7, 0xD2, 0x13, 0x01, 0x1D, 0xBE, 0xE4, 0xBF, 0x62, 0x35, 0x28, 0xC7, 0xBD, 0x26, 0x4D, 0xB2, 0xD9, 0x4D, 0x89, 0x0F, 0x23, 0x76, 0xF5, 0x0A, 0x4F, 0xBA, 0x2A, 0xDB, 0x91, 0x59, 0xD0, 0x0E, 0xA9, 0x25, 0xAC, 0x87, 0xBA, 0xB4, 0x11, 0x0D, 0xB8, 0x76, 0x42, 0x80, 0xEC, 0xAB, 0x3C, 0xBD, 0xF9, 0xD1, 0x88, 0x21, 0xBE, 0x33, 0x6B, 0x62, 0xA6, 0x9B, 0x60, 0x58, 0xF6, 0x48, 0x42, 0xE8, 0x6E, 0x0D, 0x61, 0xEB, 0xF5, 0x89, 0xB9, 0xA4, 0x4A, 0x0D, 0x71, 0x90, 0x46, 0x21, 0x4B, 0x68, 0xFB, 0xBB, 0xC5, 0x8F, 0xE1, 0x2E, 0xED, 0x55, 0x43, 0x4A, 0xF7, 0xA3, 0x39, 0x97, 0xFD, 0xFE, 0xAE, 0xE0, 0x43, 0x61, 0xE4, 0xF5, 0x19, 0xC5, 0xE7, 0xA1, 0x17, 0x28, 0xF4, 0x5F, 0x8D, 0xFB, 0xBE, 0x7D, 0x29, 0xF0, 0x9B, 0x30, 0x36, 0xCB, 0x19, 0x5A, 0xE7, 0x0F, 0xA9, 0x63, 0xA9, 0x53, 0x2E, 0xCD, 0xAD, 0x85, 0x1F, 0x8C, 0x8E, 0xC2, 0x02, 0xD0, 0xC0, 0xB1, 0xF3, 0xB3, 0xC2, 0x7F, 0x4F, 0x2A, 0x77, 0x7E, 0x41, 0xAB, 0xD4, 0x27, 0xF5, 0x86, 0xD9, 0xD8, 0x6E, 0x1B, 0x55, 0x8D, 0xB8, 0x7A, 0x4F, 0x13, 0xEF, 0x4B, 0x0D, 0x76, 0x2D, 0x2D, 0xBA, 0x3E, 0xE7, 0x72, 0x53, 0xA7, 0xF7, 0x10, 0x28, 0xB3, 0x81, 0xC8, 0xF3, 0xEB, 0x84, 0xBD, 0x16, 0xFA, 0xC0, 0x50, 0x3C, 0xD7, 0x81, 0xE2, 0x22, 0xE4, 0x17, 0x7F, 0x80, 0x05, 0x4F, 0xB6, 0x09, 0x8C, 0x79, 0x18, 0x57, 0x38, 0x94, 0x51, 0x37, 0xC7, 0x19, 0x3A, 0xA2, 0x73, 0xA8, 0x22, 0xE8, 0x66, 0xA2, 0xDF, 0x53, 0x8D, 0xF5, 0x98, 0xF5, 0xE1, 0xB4, 0xF3, 0xB5, 0xDF, 0xD4, 0x97, 0x23, 0xC8, 0x2F, 0x2B, 0x0E, 0x62, 0x1D, 0xB7, 0x5F, 0xF8, 0xC6, 0x78, 0x50, 0xE2, 0xF7, 0x0E, 0x43, 0x46, 0x82, 0x2C, 0x24, 0xE1, 0xD1, 0x7C, 0xA0, 0x56, 0x31, 0x69, 0x0F, 0x61, 0x05, 0x72, 0x75, 0x68, 0xC2, 0x7D, 0x09, 0xF4, 0x9A, 0x8D, 0x7E, 0xDC, 0x6A, 0x8C, 0x11, 0x18, 0x9F, 0xD9, 0x5D, 0x48, 0x47, 0xA9, 0xCF, 0xC4, 0x9A, 0x1C, 0xDD, 0xDB, 0x44, 0x16, 0x7D, 0x04, 0x31, 0xA2, 0x25, 0xAC, 0x7E, 0x65, 0xD3, 0x8A, 0xC8, 0x9E, 0x97, 0x96, 0x4F, 0x7C, 0x17, 0x01, 0x3F, 0xA3, 0xE6, 0xE9, 0xF6, 0x88, 0x78, 0xB7, 0xCC, 0x18, 0xDD, 0xA3, 0x4C, 0xCD, 0xC1, 0xC8, 0x42, 0xDD, 0x2B, 0xA5, 0x8A, 0x27, 0x43, 0x18, 0xA2, 0x75, 0x74, 0x79, 0x32, 0x41, 0x5A, 0x2C, 0x3E, 0xEB, 0x31, 0x27, 0x1B, 0x93, 0x65, 0x8F, 0x7D, 0x44, 0x17, 0x0C, 0xA5, 0x18, 0xC4, 0x4B, 0x2F, 0x57, 0x17, 0x70, 0xC0, 0xC3, 0xBE, 0x1B, 0x75, 0xC6, 0x80, 0xE6, 0xBB, 0x06, 0x0D, 0x05, 0xE9, 0x0D, 0x45, 0xF6, 0xAF, 0xFD, 0xA6, 0x47, 0x40, 0xBC, 0x47, 0x76, 0x28, 0x6A, 0x37, 0xAC, 0x1D, 0x0C, 0x12, 0x78, 0x78, 0x52, 0xC4, 0x2A, 0x64, 0x50, 0xDD, 0x17, 0x3F, 0x01, 0x51, 0x2B, 0xCE, 0x90, 0x52, 0xAF, 0xEA, 0x0D, 0xE9, 0x8C, 0x03, 0x96, 0xBA, 0x97, 0xF0, 0x0D, 0x17, 0x69, 0xA8, 0x0C, 0x35, 0xA3, 0x8A, 0xA2, 0x4A, 0xA7, 0xE1, 0xA0, 0xF9, 0x0D, 0xB2, 0x1C, 0x0B, 0x61, 0x8D, 0xFA, 0xD9, 0x5D, 0x69, 0xBF, 0x56, 0x43, 0x4E, 0xA1, 0xF3, 0xAE, 0x6E, 0xB5, 0xF4, 0xA1, 0xDE, 0x23, 0xAB, 0x3A, 0x6B, 0xC4, 0x36, 0x00, 0x68, 0x2C, 0xAC, 0x92, 0x7A, 0x53, 0xCA, 0x11, 0x9A, 0x9A, 0x24, 0x81, 0x9D, 0x6E, 0x8E, 0xDF, 0x48, 0x8D, 0x19, 0x80, 0x30, 0xA6, 0x60, 0xCF, 0x44, 0xB6, 0xB7, 0x1F, 0x06, 0x54, 0x98, 0xEC, 0xD9, 0x49, 0xF1, 0xFC, 0x62, 0x1D, 0x52, 0xC6, 0xEF, 0xBA, 0x71, 0x57, 0xE6, 0x23, 0x0D, 0x2C, 0xA8, 0x9C, 0x47, 0xCA, 0xF8, 0x0C, 0xA9, 0x4D, 0x32, 0x81, 0x33, 0x81, 0x01, 0x30, 0x03, 0x34, 0xE5, 0x18, 0x3C, 0x9B, 0xC5, 0xD6, 0x5A, 0xE7, 0xC7, 0x10, 0xFC, 0xF7, 0xA2, 0xE2, 0xE2, 0x3D, 0x50, 0xE3, 0x54, 0xEB, 0xB6, 0xCE, 0xCB, 0x65, 0x0C, 0xB9, 0xC7, 0xC7, 0xF8, 0xB2, 0x82, 0xC5, 0x12, 0xF7, 0xB1, 0x46, 0xA4, 0x4E, 0x54, 0xFB, 0x02, 0xE3, 0x19, 0x95, 0x3C, 0x8F, 0x95, 0x3C, 0x57, 0x8F, 0x25, 0x4E, 0xD2, 0x1B, 0x12, 0x8A, 0xB6, 0x60, 0x35, 0x08, 0x55, 0x79, 0x1D, 0xCB, 0xF2, 0xA3, 0xCC, 0xCB, 0xD9, 0x0E, 0x98, 0xC0, 0x7C, 0x0E, 0xE7, 0xF5, 0x54, 0x24, 0xA9, 0x48, 0xAC, 0xF6, 0x98, 0xF6, 0x8E, 0x40, 0x2F, 0x58, 0x77, 0x9F, 0xCA, 0x09, 0x15, 0x3F, 0xA5, 0x89, 0xC4, 0xDE, 0xFD, 0x6E, 0x16, 0x73, 0x0F, 0x3C, 0x34, 0xB5, 0x82, 0x72, 0xEE, 0x3D, 0x7C, 0xE0, 0x33, 0xB4, 0xF7, 0x21, 0xA5, 0x5B, 0x11, 0xC7, 0xFD, 0x52, 0xDF, 0x6B, 0xEB, 0xFD, 0x16, 0x44, 0x27, 0x0B, 0x0A, 0xC6, 0x36, 0x00, 0x5D, 0x81, 0x11, 0xB6, 0xFA, 0x72, 0x5C, 0xAA, 0xF3, 0xA0, 0x79, 0x9E, 0x45, 0x57, 0xC8, 0x01, 0xDC, 0x9C, 0xB6, 0x8C, 0x16, 0x11, 0x46, 0x93, 0x99, 0xE1, 0xE5, 0xFA, 0xFA, 0xBE, 0x1B, 0x68, 0xF7, 0x1D, 0x6C, 0x2D, 0xFA, 0x41, 0x6A, 0x51, 0x22, 0xDC, 0x82, 0x52, 0x80, 0x30, 0xBD, 0x1F, 0xBE, 0x16, 0x8D, 0x7B, 0x20, 0xD5, 0xF3, 0x91, 0x40, 0xA3, 0x2B, 0x9B, 0x77, 0xB8, 0x40, 0x76, 0x77, 0xD9, 0x00, 0x70, 0x07, 0xB0, 0x48, 0xB9, 0x79, 0xB9, 0xAD, 0x2C, 0x9C, 0x6F, 0xCE, 0xA1, 0xC2, 0xAB, 0x16, 0x58, 0x5A, 0xEE, 0x0F, 0x3C, 0x3F, 0x0A, 0x9A, 0xDD, 0xA8, 0x21, 0xBC, 0x82, 0x9E, 0x44, 0xEF, 0x57, 0x8F, 0x67, 0xCA, 0x10, 0x21, 0x58, 0xD2, 0x14, 0xF6, 0x2C, 0xD5, 0x47, 0xE2, 0xD9, 0x13, 0x44, 0x33, 0x90, 0xCB, 0x88, 0x23, 0xEA, 0x56, 0x02, 0xE1, 0xF8, 0x85, 0x4A, 0x74, 0xE4, 0xCB, 0x47, 0x3B, 0xA0, 0x01, 0x68, 0x4B, 0xEA, 0x50, 0x9A, 0x47, 0x01, 0x3F, 0x43, 0x6D, 0x62, 0x47, 0x99, 0x50, 0xBA, 0x76, 0x43, 0x32, 0x5E, 0x4B, 0xD0, 0x84, 0x36, 0xFC, 0x05, 0x4B, 0x12, 0x10, 0xF5, 0xF2, 0x73, 0xD4, 0x92, 0x43, 0x3C, 0x9D, 0xC0, 0x06, 0xF7, 0x9B, 0x44, 0x0D, 0x04, 0x91, 0xF2, 0x2E, 0xDD, 0xF7, 0xF8, 0xFD, 0x99, 0x2F, 0x59, 0x01, 0x1B, 0xFE, 0x21, 0x59, 0xB7, 0x1A, 0x15, 0xE7, 0x30, 0x9C, 0x38, 0xAC, 0xDB, 0xA4, 0xB4, 0x4E, 0xB1, 0x12, 0xBE, 0xF4, 0x55, 0x3A, 0x09, 0xB2, 0x7B, 0x3D, 0x10, 0x85, 0x54, 0xDC, 0x52, 0x20, 0x58, 0x6D, 0x16, 0x5A, 0x7D, 0x1C, 0x1B, 0x08, 0xA5, 0x3E, 0xA7, 0xBC, 0x56, 0xC4, 0x4E, 0xC9, 0x84, 0x7E, 0xA9, 0xE4, 0x3A, 0xC1, 0x48, 0x49, 0xD5, 0x25, 0xD0, 0x0B, 0x1E, 0x3A, 0x2B, 0xE5, 0x7A, 0xDC, 0xB8, 0xF9, 0x86, 0xCE, 0xD0, 0x55, 0x36, 0xA6, 0x68, 0x41, 0x32, 0x14, 0x9D, 0x2F, 0x07, 0x9A, 0x30, 0x21, 0xA6, 0x43, 0x02, 0x41, 0x13, 0x3D, 0x9B, 0xCB, 0x92, 0x1D, 0xA3, 0x3E, 0x6A, 0x65, 0xA8, 0x2B, 0x27, 0x25, 0x6A, 0x8A, 0x6B, 0xF4, 0x7B, 0xD1, 0xA5, 0x8F, 0x6B, 0xBA, 0xE1, 0xF3, 0xCB, 0x17, 0xBA, 0xA0, 0x16, 0xA4, 0xBA, 0xB2, 0x7A, 0x12, 0x40, 0xD6, 0x21, 0x48, 0x5F, 0x62, 0xF7, 0x1E, 0x8F, 0xEE, 0xA4, 0xE7, 0xE8, 0x44, 0x2C, 0xB9, 0x23, 0x08, 0x10, 0x5A, 0xCB, 0x4C, 0x29, 0xC9, 0xAE, 0xFC, 0x80, 0x12, 0x60, 0xE4, 0x47, 0xA5, 0xE3, 0xAC, 0x8A, 0x65, 0x36, 0x7D, 0x8D, 0x27, 0xEA, 0x97, 0x2F, 0x24, 0x1B, 0x5E, 0xF8, 0x84, 0x9C, 0xAD, 0x4A, 0x53, 0x66, 0x61, 0xC5, 0xE0, 0xAE, 0xBE, 0x47, 0xAE, 0xE0, 0x84, 0x2F, 0xDF, 0x08, 0xBF, 0xFC, 0x6A, 0x70, 0x0A, 0xDD, 0xD0, 0xBB, 0xAE, 0x4E, 0xBA, 0x6F, 0x90, 0x2D, 0xB6, 0xEB, 0x8D, 0xCA, 0xDB, 0xA0, 0x80, 0x0B, 0x31, 0x44, 0x14, 0xEF, 0x33, 0x73, 0x1B, 0xA2, 0xE4, 0xA0, 0x09, 0xD8, 0xF7, 0xE2, 0xEE, 0x42, 0x4B, 0x49, 0x11, 0x8E, 0xFC, 0x26, 0x3F, 0xCE, 0x54, 0x04, 0x96, 0xFB, 0x14, 0x7B, 0x43, 0x3A, 0xC7, 0x97, 0xF2, 0xB6, 0xF4, 0xB8, 0xCF, 0x8F, 0x3F, 0x57, 0x2E, 0x09, 0xE7, 0xF8, 0x7D, 0xE4, 0x25, 0xEB, 0x98, 0xA1, 0x36, 0xA9, 0x58, 0xD9, 0x41, 0x48, 0x4D, 0x02, 0x39, 0x52, 0x8D, 0xAE, 0xDA, 0x4F, 0xAD, 0x3C, 0x56, 0xC0, 0xF5, 0xC1, 0x62, 0x39, 0x72, 0xE1, 0x3E, 0x4F, 0xFC, 0xB0, 0x8C, 0xD4, 0xD8, 0x01, 0xBE, 0x24, 0x45, 0xFA, 0xC0, 0x45, 0xBF, 0x77, 0x90, 0x57, 0x31, 0xEC, 0xCE, 0x49, 0x26, 0xB1, 0x82, 0x1F, 0xAC, 0x4C, 0x3E, 0xE6, 0xBE, 0xBF, 0xE5, 0xEB, 0x6D, 0x04, 0xB2, 0x06, 0x36, 0x5C, 0xCC, 0xB8, 0x08, 0x18, 0x2B, 0x05, 0x8B, 0xF6, 0xE4, 0x07, 0x27, 0x8B, 0x17, 0xD1, 0x41, 0x65, 0xFA, 0x55, 0xEF, 0x1F, 0x2C, 0xE7, 0x10, 0x9C, 0x85, 0x27, 0xDC, 0x72, 0xD6, 0x85, 0x8C, 0x96, 0x7D, 0x56, 0xAE, 0xD7, 0xE3, 0x39, 0x2C, 0x30, 0x84, 0x21, 0x94, 0x1D, 0x53, 0x68, 0xD1, 0xE5, 0x81, 0xD9, 0x36, 0x4C, 0x2E, 0x45, 0x42, 0xA7, 0x72, 0x37, 0xBE, 0x75, 0x2C, 0x80, 0x49, 0x29, 0xE5, 0xA9, 0xEC, 0xED, 0x8D, 0x5F, 0x6E, 0x00, 0xE8, 0x59, 0x69, 0x01, 0x7B, 0xBF, 0x5C, 0xC4, 0x71, 0x52, 0xF4, 0x6B, 0x4D, 0x11, 0x2F, 0x10, 0x37, 0xEE, 0x65, 0x60, 0xD0, 0x59, 0xEA, 0x03, 0x23, 0xFA, 0x94, 0xFD, 0xE5, 0x12, 0xBD, 0x3F, 0x8E, 0x42, 0x53, 0xF0, 0xC4, 0xBA, 0x73, 0x9C, 0x0C, 0x96, 0xF1, 0xC1, 0xCF, 0xED, 0x6B, 0x1C, 0xD2, 0xB4, 0x4F, 0x4B, 0x3A, 0x39, 0x0A, 0x26, 0x42, 0xC0, 0x0E, 0xE5, 0x94, 0x0F, 0xF7, 0x7A, 0xE9, 0xD7, 0x73, 0x82, 0xB3, 0xCA, 0x96, 0x70, 0xC3, 0xC2, 0x61, 0x85, 0xAE, 0x3E, 0xD7, 0xD6, 0x00, 0x0D, 0x83, 0x7E, 0x45, 0x81, 0xF9, 0x87, 0x18, 0xC7, 0x15, 0xF9, 0xB8, 0x04, 0x4A, 0xA1, 0x1F, 0x71, 0xE7, 0xC5, 0xAF, 0xFE, 0x96, 0xBE, 0xB8, 0x02, 0x49, 0xDA, 0x38, 0xE8, 0x14, 0x5B, 0xBE, 0x28, 0x6C, 0xC3, 0x84, 0x50, 0x7D, 0x49, 0x82, 0x7A, 0x1D, 0x06, 0x20, 0xC1, 0x25, 0xE8, 0x05, 0x3D, 0xB8, 0x03, 0x73, 0x4F, 0x1B, 0xC4, 0x8D, 0xFB, 0x94, 0xA5, 0x86, 0x9C, 0x32, 0x10, 0xC7, 0x45, 0xA0, 0xD1, 0xD2, 0x67, 0xD7, 0x77, 0x38, 0x27, 0xC3, 0xBB, 0xD4, 0x58, 0x6E, 0xC9, 0xFE, 0x62, 0xBC, 0xAE, 0xC8, 0x9B, 0x9B, 0x25, 0xD1, 0x1C, 0x30, 0xBE, 0x74, 0x13, 0x8A, 0xFB, 0xBB, 0xCC, 0x0F, 0x86, 0x44, 0xCE, 0x2D, 0x54, 0x5E, 0xEF, 0x47, 0xD0, 0x67, 0x2F, 0x93, 0x91, 0xD1, 0xBE, 0x01, 0x10, 0x03, 0xBB, 0xFD, 0xD4, 0x60, 0x23, 0x60, 0x4F, 0xF8, 0x63, 0x3C, 0xEF, 0x9B, 0x7D, 0x23, 0x48, 0x99, 0x61, 0x32, 0x3D, 0xAF, 0x14, 0x8D, 0x08, 0x20, 0x26, 0x24, 0x22, 0x94, 0x0F, 0x27, 0x0C, 0xA7, 0x44, 0x46, 0x91, 0x9B, 0x7F, 0xAE, 0x6F, 0x34, 0xBC, 0x5F, 0x1A, 0xE5, 0xAF, 0x3A, 0xDE, 0x4A, 0x64, 0xA2, 0xDB, 0xC9, 0x56, 0xBC, 0x54, 0x62, 0x4B, 0xCC, 0xF9, 0x38, 0xBC, 0x93, 0x12, 0x4C, 0x1C, 0x90, 0x31, 0x0E, 0x7A, 0x3C, 0xE5, 0xF6, 0x04, 0x25, 0x14, 0x12, 0xD4, 0x1F, 0xA4, 0xDA, 0xF5, 0x9B, 0x62, 0x85, 0xAA, 0x2E, 0xD0, 0xB7, 0x20, 0xD5, 0xDF, 0x99, 0xBA, 0x27, 0xA0, 0x7D, 0x8A, 0xA4, 0x7C, 0x3B, 0x73, 0x41, 0xF8, 0x7E, 0x1E, 0x25, 0xBB, 0xD7, 0xD5, 0x56, 0xA2, 0xCB, 0x0F, 0x98, 0xCC, 0xDC, 0xF6, 0xCC, 0xEA, 0x00, 0x50, 0x17, 0x06, 0x8B, 0x5B, 0x58, 0xA4, 0x73, 0xE3, 0x98, 0xA7, 0xC9, 0x56, 0x54, 0x39, 0xF4, 0x5C, 0xB1, 0x7F, 0xD9, 0x11, 0xB1, 0xF7, 0x59, 0xD2, 0xBE, 0x79, 0x26, 0xE1, 0x1E, 0xE7, 0xE3, 0x6E, 0x67, 0x4F, 0x73, 0x6B, 0xBE, 0xCF, 0xC0, 0xCA, 0x51, 0x44, 0x05, 0x52, 0xA8, 0xDD, 0x89, 0x13, 0xD1, 0x66, 0x0C, 0xAF, 0xE9, 0x13, 0x49, 0x71, 0x5F, 0xF1, 0xD8, 0xC9, 0xDF, 0xA1, 0xE9, 0xD3, 0x3B, 0x9E, 0x73, 0x17, 0xF3, 0x0F, 0x83, 0xBC, 0x4F, 0x2A, 0xD8, 0x92, 0x88, 0x92, 0x61, 0xD5, 0x18, 0x80, 0x9E, 0x26, 0xD2, 0xC8, 0xC7, 0xAE, 0xEC, 0xEB, 0x9E, 0xC8, 0xE5, 0xEE, 0x66, 0x7E, 0x29, 0x12, 0xC1, 0x47, 0xF4, 0x72, 0xAA, 0x87, 0x00, 0x9F, 0xC9, 0xF3, 0x71, 0x65, 0x6D, 0xFC, 0xDE, 0x50, 0xF0, 0xCD, 0xF0, 0xDE, 0x44, 0xA0, 0xC3, 0x20, 0xB3, 0xBE, 0xD4, 0x06, 0x7B, 0x55, 0x56, 0xA3, 0xF5, 0x7E, 0xE6, 0x9F, 0x9A, 0xCA, 0x0F, 0xA8, 0x2C, 0x0A, 0x9F, 0xE9, 0x11, 0x78, 0x22, 0x1B, 0x43, 0xB6, 0x4E, 0xDE, 0x4E, 0xC5, 0x55, 0x09, 0x83, 0x20, 0x13, 0x63, 0x57, 0xB3, 0x46, 0x31, 0xAD, 0x9D, 0xCC, 0x3E, 0xDB, 0x23, 0xBC, 0x18, 0x4E, 0x10, 0xEA, 0xF4, 0x13, 0x38, 0xD1, 0xC5, 0x9B, 0x4C, 0xD2, 0x84, 0x76, 0x6A, 0x03, 0x9E, 0xF6, 0xE6, 0xE0, 0x13, 0x4E, 0xC4, 0x0C, 0x0C, 0x20, 0xE0, 0xEC, 0xBC, 0x55, 0xEF, 0x73, 0xDC, 0x21, 0x13, 0xD7, 0xF7, 0xDB, 0x30, 0xF5, 0xA5, 0xB6, 0x84, 0x89, 0xE0, 0x34, 0x4F, 0x17, 0x03, 0x36, 0x9D, 0x04, 0xE7, 0xEE, 0x7A, 0xAB, 0xCF, 0x8B, 0xA1, 0x8A, 0x50, 0x57, 0x61, 0x67, 0x89, 0xD7, 0xFD, 0xA2, 0xE4, 0x5E, 0x45, 0x92, 0x17, 0xAE, 0x26, 0x1B, 0x0B, 0x41, 0x8D, 0xE9, 0xFE, 0x2E, 0x39, 0xEF, 0xC1, 0xC6, 0x53, 0x36, 0xD0, 0xA1, 0xDB, 0x34, 0x8C, 0xB3, 0x33, 0x69, 0xBE, 0xA4, 0x35, 0xB5, 0xDD, 0xC4, 0x9C, 0x9C, 0xC8, 0x00, 0x8A, 0x6B, 0x3B, 0x84, 0x95, 0x21, 0xA7, 0xC9, 0xA1, 0x75, 0xF9, 0x76, 0xFB, 0x23, 0x56, 0x5A, 0x35, 0xF5, 0x59, 0x88, 0xD6, 0xEA, 0xB7, 0x46, 0x2A, 0x2F, 0xA5, 0x1E, 0x0A, 0x3D, 0x14, 0x0F, 0x36, 0xEA, 0x0F, 0x33, 0xA4, 0x29, 0x61, 0x56, 0x7D, 0x5D, 0x60, 0xD4, 0xA5, 0x9C, 0xAD, 0x2C, 0x56, 0x5E, 0x3C, 0x9B, 0xB5, 0x10, 0x9B, 0xCB, 0x99, 0xB4, 0x5C, 0x97, 0x6D, 0x05, 0x49, 0x29, 0x52, 0x0A, 0xCE, 0x61, 0xB7, 0xD7, 0x78, 0x49, 0xB2, 0x5B, 0x9A, 0xC6, 0xEF, 0x11, 0x99, 0x43, 0xD2, 0x2B, 0x0C, 0xE1, 0x3C, 0x2F, 0x80, 0x36, 0x8C, 0x51, 0x5D, 0xD6, 0x70, 0x0C, 0xF7, 0x09, 0x3D, 0xCA, 0x00, 0x57, 0x44, 0x1C, 0x77, 0x78, 0xAA, 0x73, 0xF8, 0x99, 0xE7, 0xD3, 0x96, 0xD4, 0xD9, 0xAE, 0x31, 0xF0, 0xBB, 0x21, 0xAB, 0x05, 0x7D, 0x13, 0x7C, 0x73, 0x51, 0xAE, 0xE4, 0x8D, 0xBD, 0x58, 0xE6, 0x01, 0x80, 0xA7, 0xDC, 0xD0, 0xE5, 0x19, 0x48, 0x3C, 0x90, 0x6D, 0x12, 0xFF, 0xF2, 0xB6, 0xBB, 0x1F, 0xC5, 0x23, 0x21, 0xA9, 0x25, 0x4F, 0xF5, 0x09, 0x18, 0xD2, 0x37, 0xC3, 0xDE, 0x2B, 0xC3, 0xE0, 0x41, 0xF3, 0x13, 0x28, 0x0B, 0xA6, 0xCF, 0xAD, 0xBE, 0x4A, 0xBD, 0xB0, 0xE0, 0x55, 0x96, 0xB8, 0x83, 0xAB, 0x74, 0x72, 0xEB, 0x75, 0x0C, 0x8F, 0xB4, 0xC8, 0xA2, 0x0D, 0xC9, 0xB3, 0xF5, 0xFA, 0x2C, 0x5F, 0xCD, 0x1C, 0x58, 0xE5, 0x5B, 0x8A, 0xBC, 0xE0, 0x93, 0xAD, 0x44, 0x29, 0xE1, 0x93, 0x01, 0xB4, 0x73, 0xE5, 0x98, 0x53, 0x35, 0xD7, 0x23, 0xA3, 0x77, 0xD0, 0xF6, 0xF6, 0xFC, 0xD9, 0x8E, 0xBE, 0xEC, 0x63, 0xB8, 0x6F, 0xF6, 0xE3, 0x7C, 0xA1, 0xF5, 0xE9, 0xB1, 0x7B, 0x2B, 0xD5, 0x30, 0x24, 0x6A, 0x77, 0xC4, 0x58, 0x1D, 0x6E, 0x83, 0xF6, 0x01, 0x5C, 0xE9, 0x88, 0xF6, 0x76, 0xC3, 0x5E, 0x35, 0x6D, 0x95, 0x68, 0xF4, 0x7A, 0x0C, 0x71, 0x9A, 0xAB, 0x13, 0xAA, 0x33, 0x56, 0x31, 0xCF, 0x09, 0x9A, 0x11, 0x68, 0xDA, 0xAD, 0x2F, 0xCD, 0x03, 0x89, 0x8E, 0x0F, 0xF7, 0x1D, 0xFC, 0xE4, 0x51, 0xB9, 0x73, 0x7C, 0xFA, 0x0D, 0xC1, 0x2E, 0xC3, 0xED, 0xDF, 0x75, 0x76, 0x27, 0x61, 0x80, 0xC1, 0xE3, 0xC8, 0x64, 0x8C, 0xC7, 0x87, 0x23, 0x04, 0x44, 0xD0, 0x73, 0xE3, 0xA0, 0x05, 0xDB, 0x1C, 0x7A, 0x99, 0x29, 0x93, 0x7F, 0xF8, 0x37, 0x87, 0xD6, 0x27, 0x3D, 0x8E, 0x47, 0x93, 0x81, 0x3D, 0x1C, 0x16, 0x1A, 0xC8, 0xB8, 0xE2, 0x87, 0x7A, 0xBD, 0x90, 0x76, 0x04, 0xB0, 0xDF, 0xD3, 0x9D, 0x42, 0x2F, 0x7A, 0x9D, 0x7B, 0xD8, 0x03, 0xC7, 0xFD, 0xF2, 0x1F, 0xFF, 0xC3, 0xBF, 0x4C, 0xBA, 0xFE, 0x3C, 0x92, 0x7E, 0xFF, 0xED, 0x17, 0xC9, 0x70, 0xDD, 0x9F, 0x2F, 0xC8, 0xFE, 0x78, 0x3F, 0xF6, 0xCB, 0x5F, 0x7F, 0x05, 0x6B, 0xF8, 0x5F, 0x66, 0x7A, 0xC1, 0x3D, 0xFF, 0xF7, 0x4B, 0xFD, 0x22, 0x7F, 0xFD, 0x75, 0x9B, 0x93, 0xF1, 0x9F, 0x0C, 0x96, 0xD3, 0xB8, 0xFF, 0xA9, 0x4C, 0x86, 0xA6, 0xBF, 0xFF, 0xFC, 0x83, 0xFB, 0x5A, 0x4D, 0xD7, 0xE6, 0xFB, 0xD4, 0xCF, 0x4E, 0xFE, 0xF8, 0xD9, 0xCB, 0x1F, 0x7F, 0x74, 0xF3, 0xC7, 0xF9, 0x6B, 0xDE, 0x9C, 0x3F, 0x9A, 0xFC, 0xF7, 0x2E, 0x6C, 0xCD, 0xCF, 0xD7, 0x77, 0x7F, 0xB3, 0x90, 0x37, 0xDB, 0xDC, 0x27, 0xF7, 0x9F, 0x9B, 0xB1, 0x6F, 0xC6, 0xE2, 0x4F, 0x69, 0x3F, 0x65, 0xDD, 0x5F, 0x7E, 0x0E, 0xEB, 0xFB, 0xC0, 0x5F, 0x7F, 0x4D, 0xD7, 0xBF, 0xFE, 0xBD, 0x1F, 0x7E, 0x05, 0x7F, 0x76, 0xE0, 0xE7, 0xB8, 0x91, 0xFF, 0xA7, 0x71, 0x7F, 0x8B, 0xEB, 0xBF, 0x57, 0x3E, 0xFC, 0xBF, 0xFC, 0xED, 0xF8, 0xF7, 0x73, 0xFB, 0x7F, 0xF9, 0xB7, 0x1F, 0xFF, 0x03, 0xC7, 0xFD, 0xFF, 0xBF, 0xAC, 0xFF, 0x94, 0xFC, 0x53, 0xD6, 0x9F, 0x8C, 0x77, 0x3C, 0x17, 0x8D, 0x6F, 0x9C, 0xCA, 0x40, 0x2F, 0x5F, 0x06, 0xE9, 0x86, 0xD3, 0xE4, 0x3A, 0x7A, 0xD6, 0x16, 0xFB, 0x2F, 0x36, 0xB3, 0x92, 0xDB, 0x4E, 0x9B, 0xD0, 0x38, 0x9E, 0x1F, 0x74, 0x7E, 0xD0, 0x4B, 0xEA, 0x96, 0xB5, 0x5F, 0x51, 0x36, 0x4D, 0xB2, 0x25, 0x61, 0x9F, 0x7E, 0x40, 0xF5, 0xD8, 0x11, 0xC2, 0xB2, 0xBB, 0xD8, 0xCF, 0xCB, 0x0E, 0x6D, 0x9B, 0x89, 0x04, 0x7B, 0x53, 0x3F, 0xAE, 0x66, 0xD7, 0xA3, 0xCA, 0xBC, 0x38, 0xF7, 0x23, 0x27, 0xC9, 0x26, 0xDD, 0xBD, 0xA1, 0xFA, 0x5A, 0xDF, 0x17, 0xDD, 0x93, 0x83, 0x27, 0x67, 0x23, 0x77, 0xB9, 0xF5, 0x9E, 0x5F, 0x29, 0x3A, 0x65, 0xA1, 0xA3, 0x55, 0xCA, 0x07, 0x58, 0x00, 0x03, 0xBE, 0x9F, 0xE8, 0x01, 0x02, 0xE5, 0x4A, 0x93, 0x25, 0x26, 0x7F, 0xBD, 0x45, 0xDB, 0xFC, 0x56, 0x1F, 0xFD, 0x25, 0xBD, 0xB1, 0xE1, 0x4D, 0xCA, 0x5A, 0x33, 0xBD, 0xC7, 0x8D, 0x95, 0xCC, 0x78, 0x30, 0xE9, 0xE8, 0xB8, 0x68, 0x04, 0x91, 0xB5, 0xAA, 0x75, 0x35, 0x41, 0x66, 0x0B, 0x8A, 0xC9, 0xC6, 0xD7, 0xBD, 0xCD, 0xB7, 0xD3, 0xB9, 0xE2, 0x18, 0x4B, 0x9E, 0x42, 0x14, 0x5F, 0x77, 0xE8, 0x42, 0x91, 0x6B, 0x56, 0xCE, 0xE8, 0xF5, 0x9C, 0x84, 0xBD, 0x89, 0x90, 0x2E, 0x64, 0x28, 0xE5, 0xCE, 0xB6, 0x65, 0x5A, 0x61, 0x5C, 0x36, 0xEE, 0xE4, 0x2B, 0x89, 0x8F, 0x6C, 0x34, 0xEF, 0xAB, 0x74, 0xB3, 0x77, 0xE5, 0x67, 0xD2, 0x75, 0x75, 0x36, 0x03, 0xF2, 0xE1, 0x80, 0xD0, 0x0F, 0x89, 0xD5, 0x24, 0x93, 0x34, 0xEB, 0x42, 0x18, 0xD1, 0x88, 0xE3, 0xE6, 0x98, 0x9E, 0x3B, 0x31, 0xFB, 0x25, 0x94, 0x18, 0x32, 0x7F, 0xB1, 0xAA, 0xDB, 0xAD, 0x8A, 0xDC, 0xC2, 0x6E, 0xA2, 0x6D, 0x4F, 0x7A, 0x17, 0x7B, 0xF8, 0xA5, 0x4C, 0x6F, 0x1D, 0x88, 0x0A, 0xB4, 0xA2, 0xF0, 0x27, 0x5F, 0xF6, 0x4A, 0x64, 0x85, 0xEB, 0x1A, 0x41, 0x0A, 0xC1, 0x5C, 0x9F, 0xC3, 0x98, 0xAB, 0x42, 0xD3, 0x5A, 0xB1, 0xC9, 0x8A, 0xE7, 0xDA, 0xF0, 0x88, 0x59, 0xCF, 0x63, 0x24, 0x95, 0x19, 0x21, 0x86, 0xAE, 0x90, 0x4F, 0x99, 0x9A, 0x72, 0xB4, 0x88, 0x0C, 0x3B, 0x6C, 0x54, 0x5F, 0xF7, 0x97, 0x4A, 0x21, 0xE6, 0x8D, 0xA7, 0x15, 0x57, 0xAE, 0x22, 0x2D, 0x67, 0xA3, 0xA2, 0x32, 0x62, 0x10, 0xF4, 0xF8, 0xBA, 0x0E, 0xFB, 0x31, 0x30, 0xEA, 0x63, 0x97, 0x18, 0x6B, 0xCE, 0xB7, 0x47, 0xEB, 0x44, 0x30, 0xCA, 0xDA, 0x0C, 0x5C, 0x8C, 0x56, 0xBD, 0x5E, 0x8C, 0x8C, 0xA8, 0x64, 0x7D, 0x80, 0x95, 0xF1, 0x85, 0x63, 0xF1, 0xB9, 0x02, 0xF5, 0x50, 0x49, 0xAB, 0x7A, 0xD7, 0xCC, 0xD9, 0xD5, 0x0C, 0x7F, 0x49, 0x6D, 0xC5, 0x42, 0xF3, 0x18, 0xE8, 0xB1, 0x71, 0x42, 0xC0, 0xFE, 0x12, 0x93, 0x99, 0x78, 0x61, 0x28, 0x9A, 0x65, 0x08, 0x0C, 0x2B, 0x24, 0x70, 0xD5, 0xB9, 0xB6, 0x3E, 0x74, 0xC5, 0xE7, 0x07, 0xF5, 0x95, 0x30, 0x50, 0x0B, 0x50, 0x63, 0x08, 0x91, 0xA8, 0xAD, 0x21, 0x3E, 0xA0, 0x5F, 0x88, 0xCD, 0x4E, 0x57, 0xB0, 0x05, 0xCD, 0x21, 0x4A, 0x68, 0x7E, 0xE1, 0xC5, 0x25, 0x3A, 0xD0, 0x4D, 0x82, 0x96, 0xBF, 0x4B, 0x95, 0xE2, 0xD8, 0x72, 0x51, 0xF5, 0x3E, 0x03, 0x0A, 0x03, 0xAF, 0xCC, 0xA6, 0xA0, 0x97, 0xEE, 0x93, 0x3A, 0xB9, 0x58, 0x2D, 0x66, 0xF9, 0x26, 0x3B, 0xCD, 0x05, 0x68, 0x52, 0xD2, 0x3E, 0xD8, 0x1B, 0x0B, 0x29, 0x6A, 0x59, 0xBE, 0xBE, 0x6D, 0x44, 0x10, 0xF0, 0x26, 0x17, 0xB9, 0xF3, 0x9B, 0xC6, 0x6D, 0x67, 0xE0, 0xDC, 0x69, 0xE9, 0x03, 0xA8, 0xDB, 0x46, 0x0E, 0x1D, 0xFC, 0x92, 0x41, 0x6C, 0x3E, 0x80, 0xEC, 0xA3, 0x32, 0xF4, 0x29, 0xC5, 0x36, 0xCD, 0x61, 0xBC, 0xA9, 0x0A, 0x06, 0x80, 0x99, 0x4E, 0xBB, 0xE6, 0x0A, 0xD9, 0x18, 0xE9, 0x7D, 0xF8, 0x8A, 0x35, 0x48, 0x26, 0x5E, 0x13, 0x93, 0x0F, 0xC7, 0xB5, 0x7F, 0x9D, 0x7E, 0x9B, 0xCD, 0x34, 0x37, 0x90, 0xCE, 0xB2, 0xCB, 0xB6, 0xAA, 0x77, 0x37, 0xAB, 0x37, 0xB4, 0x06, 0x15, 0xAD, 0x4F, 0x58, 0xD6, 0x21, 0x3C, 0xA9, 0xF0, 0xF5, 0x70, 0x3F, 0x38, 0x99, 0x29, 0xD4, 0xBB, 0xDD, 0x8B, 0x61, 0x8F, 0xCC, 0xD1, 0x9B, 0x30, 0xED, 0x46, 0x43, 0xEE, 0x79, 0x93, 0xBC, 0x90, 0x59, 0xD1, 0x5B, 0x70, 0x63, 0x75, 0xC0, 0xAA, 0x8C, 0xED, 0x12, 0x38, 0xDD, 0x91, 0x74, 0x1F, 0x26, 0x3A, 0xE8, 0xCB, 0x39, 0xB3, 0xDE, 0x27, 0x00, 0x0A, 0x79, 0x10, 0xF9, 0xF3, 0xA0, 0x56, 0xDF, 0x1D, 0x7B, 0x50, 0xB5, 0xD2, 0x28, 0x58, 0x4A, 0x0D, 0x16, 0xFA, 0x79, 0xF3, 0x99, 0x70, 0x8E, 0x86, 0x2A, 0x1B, 0xAD, 0xD9, 0x3D, 0x5F, 0x1E, 0xF3, 0x55, 0x32, 0x25, 0x8D, 0x27, 0xF3, 0xF2, 0x70, 0xEF, 0x87, 0x31, 0xF5, 0x42, 0x16, 0x2C, 0xB8, 0x0F, 0xD7, 0x80, 0xFC, 0x2C, 0xDB, 0x13, 0x33, 0x5E, 0xF9, 0x5D, 0x52, 0x13, 0x78, 0x9C, 0xC5, 0xA8, 0x11, 0xE8, 0x5D, 0xC6, 0x5B, 0x54, 0x07, 0x90, 0x75, 0x23, 0xC9, 0x7C, 0x2A, 0xA5, 0x4F, 0x01, 0x02, 0xEF, 0x80, 0x7C, 0xE5, 0xE6, 0x8C, 0x02, 0x87, 0xF7, 0xF3, 0xD0, 0xE4, 0x33, 0x7E, 0xE0, 0x40, 0x38, 0xFA, 0xF9, 0xAB, 0x4F, 0x17, 0x9A, 0x56, 0x35, 0x67, 0xE9, 0x21, 0xB7, 0x7C, 0x47, 0x85, 0x03, 0x09, 0x89, 0xDF, 0x5D, 0xA6, 0xDC, 0x30, 0xFC, 0x0A, 0x27, 0x7B, 0x34, 0x94, 0x56, 0x3A, 0xC3, 0x6E, 0x80, 0x17, 0x5F, 0x11, 0x37, 0xC3, 0xCB, 0x2E, 0xAE, 0x44, 0x7B, 0xD4, 0x60, 0x9B, 0xC8, 0x78, 0x7D, 0x41, 0x29, 0x0C, 0x7F, 0xA9, 0xDA, 0x8B, 0x7F, 0xD0, 0x2F, 0x23, 0x78, 0x6B, 0x46, 0xFC, 0x73, 0xBD, 0xAF, 0x97, 0xC5, 0xDA, 0x5D, 0x2F, 0x5C, 0x6C, 0xF2, 0x20, 0xE5, 0xA3, 0xC0, 0x03, 0x9C, 0x56, 0x9F, 0xCF, 0x40, 0x88, 0xAC, 0x1F, 0x09, 0x8E, 0x93, 0xC5, 0x02, 0xDA, 0x51, 0xF0, 0x62, 0x7F, 0x15, 0x32, 0x84, 0x31, 0x68, 0xC5, 0x35, 0x2C, 0x58, 0x4B, 0x7E, 0x9C, 0x54, 0xB2, 0x34, 0xAC, 0x2B, 0x50, 0x68, 0xB4, 0x17, 0x5C, 0xD3, 0x82, 0x7A, 0x2A, 0x36, 0x6B, 0x4D, 0x51, 0x36, 0x62, 0x92, 0x3A, 0x66, 0x9A, 0x9D, 0x9F, 0x33, 0x07, 0x6F, 0x38, 0x9F, 0xF3, 0x72, 0xA3, 0xDC, 0x25, 0x80, 0x48, 0xFD, 0x20, 0xE7, 0x26, 0xB3, 0xFB, 0xCF, 0xB4, 0xEB, 0x68, 0x95, 0x86, 0x5C, 0x64, 0xBB, 0x99, 0xF0, 0x32, 0x14, 0x57, 0x63, 0xD8, 0xF1, 0x19, 0x5F, 0x31, 0x41, 0x3A, 0xEF, 0xD5, 0x68, 0x1E, 0xBA, 0x06, 0xB1, 0x84, 0xD6, 0x5A, 0xD5, 0x78, 0x4D, 0x0A, 0x88, 0xE7, 0xCF, 0xEB, 0xD2, 0x89, 0x58, 0xE6, 0xAE, 0x09, 0x33, 0x3D, 0x00, 0x83, 0xF1, 0x6C, 0x21, 0xAC, 0xEE, 0x62, 0x86, 0x44, 0x63, 0x55, 0x4B, 0xDB, 0x26, 0x67, 0x88, 0x2F, 0x9E, 0x3F, 0xCF, 0xD5, 0x00, 0xEA, 0x17, 0x65, 0xDD, 0x71, 0x76, 0xB1, 0xD4, 0x86, 0x74, 0xE1, 0x4E, 0x3A, 0x51, 0xB9, 0x20, 0x02, 0xF0, 0x25, 0xF7, 0xC8, 0xE6, 0xF3, 0xAF, 0xD3, 0x3D, 0xDB, 0x41, 0x73, 0x50, 0x45, 0xD8, 0x33, 0x38, 0x06, 0xA5, 0xF0, 0xBA, 0x45, 0x82, 0x7A, 0x4B, 0xDE, 0xF3, 0x64, 0xF7, 0x6C, 0x8D, 0x17, 0x8C, 0x1C, 0x82, 0xC2, 0x4D, 0x93, 0xB0, 0x7D, 0x04, 0xAB, 0x32, 0x7A, 0xC0, 0xD4, 0x9F, 0xE9, 0xAB, 0x01, 0xE5, 0x40, 0x47, 0x76, 0xD9, 0x09, 0x17, 0xCC, 0x48, 0x0C, 0xE3, 0x26, 0xD4, 0x75, 0x7F, 0xB3, 0x9B, 0xFD, 0x29, 0xF3, 0x69, 0x8D, 0x84, 0x34, 0x6F, 0x22, 0x82, 0x5B, 0xEC, 0x8A, 0x31, 0x99, 0x4F, 0x00, 0xD5, 0xCA, 0xC1, 0x7A, 0x6F, 0xF9, 0xA3, 0x59, 0xA7, 0x2F, 0x5D, 0xFD, 0x43, 0xBE, 0x32, 0x25, 0xBC, 0x24, 0xBD, 0x56, 0xDC, 0x57, 0xE5, 0x48, 0x9F, 0x4D, 0x63, 0xF5, 0x72, 0x58, 0x9A, 0xC5, 0xFA, 0x89, 0x03, 0x4A, 0x28, 0x73, 0x20, 0x62, 0xEA, 0x2F, 0xFB, 0x0D, 0xC9, 0x14, 0xB3, 0xD3, 0x20, 0x40, 0x01, 0xA4, 0x17, 0xF3, 0x4E, 0xBB, 0xBB, 0xAB, 0x87, 0x59, 0x5F, 0x8E, 0x1C, 0xD7, 0xFA, 0x6B, 0x0F, 0x51, 0x1B, 0x72, 0x99, 0x57, 0x23, 0xD4, 0x55, 0x0A, 0x50, 0xE0, 0x92, 0x2C, 0xFE, 0x57, 0x4A, 0xD0, 0x50, 0xCF, 0x00, 0x0B, 0xD3, 0xCB, 0xAB, 0xF2, 0x8E, 0x5C, 0xA7, 0xAD, 0xD1, 0xBC, 0xA5, 0x0B, 0xE5, 0xF5, 0xD1, 0x0B, 0xBC, 0x5D, 0x08, 0xC9, 0x99, 0xBA, 0xF8, 0x01, 0x09, 0xED, 0xB4, 0xAE, 0x67, 0xD0, 0x3F, 0x5F, 0x80, 0x43, 0xD6, 0x77, 0x79, 0x63, 0x00, 0x16, 0x68, 0xD8, 0xFB, 0x45, 0x47, 0x88, 0x7E, 0x0F, 0x81, 0x27, 0xFB, 0x39, 0xE7, 0x4D, 0x8C, 0x1E, 0x2F, 0x91, 0x28, 0x24, 0x3D, 0x04, 0x6E, 0x64, 0x5C, 0xBC, 0x77, 0x0B, 0x11, 0x56, 0x8D, 0x10, 0x53, 0xAD, 0xBA, 0xDD, 0x2B, 0x42, 0x73, 0x2D, 0xA8, 0xC1, 0x7A, 0x73, 0xAE, 0x71, 0xEF, 0x46, 0x07, 0x4A, 0x24, 0xEA, 0x04, 0xB2, 0xCD, 0x55, 0x0C, 0xA3, 0xAB, 0xDF, 0x8B, 0x26, 0x6F, 0x3A, 0xAA, 0x32, 0x55, 0xCC, 0xE4, 0xC0, 0x26, 0x0B, 0x91, 0xDC, 0x8B, 0x55, 0x14, 0xE6, 0x24, 0x40, 0x61, 0x77, 0xFE, 0x35, 0x39, 0xB7, 0x8F, 0x5F, 0xD0, 0x47, 0x30, 0xF2, 0x36, 0x4B, 0xD1, 0xC2, 0x14, 0xBE, 0xB1, 0xF4, 0x6D, 0x3C, 0x90, 0x81, 0x62, 0xC6, 0x86, 0x27, 0xA5, 0x26, 0x1C, 0x9D, 0x55, 0xC0, 0x68, 0xC7, 0x32, 0x97, 0xC3, 0xC4, 0x1A, 0xFB, 0x56, 0x6A, 0x3C, 0xB5, 0x96, 0xF6, 0x6F, 0x7B, 0x3B, 0x38, 0x5C, 0x1A, 0x43, 0x32, 0x94, 0x88, 0x13, 0x53, 0x6A, 0xE9, 0x64, 0x8B, 0x37, 0x20, 0x3A, 0x70, 0x14, 0x7D, 0xD2, 0x92, 0x0F, 0x80, 0xE3, 0xA8, 0x5A, 0xC5, 0x2B, 0x04, 0xF6, 0x2D, 0xBC, 0x84, 0x2E, 0x89, 0x48, 0xF6, 0x9C, 0x34, 0x66, 0xAA, 0x3A, 0xDE, 0xDD, 0x76, 0xB5, 0xF6, 0x7C, 0xD5, 0x7C, 0x70, 0x5B, 0xC0, 0xA6, 0xAF, 0x5A, 0x8F, 0x31, 0x39, 0x12, 0x5F, 0xA4, 0x2C, 0x57, 0x71, 0x08, 0x94, 0xF4, 0x0E, 0xCF, 0xCC, 0xA7, 0x58, 0x5A, 0x97, 0xB8, 0xB1, 0x56, 0xED, 0xDB, 0xDA, 0x8F, 0x89, 0x78, 0xB0, 0x64, 0x4D, 0x6B, 0xB6, 0x7E, 0x71, 0x11, 0xA0, 0xF2, 0xA7, 0x54, 0x70, 0x62, 0xEE, 0x88, 0x78, 0x0E, 0x56, 0x9B, 0x85, 0x62, 0x96, 0xCB, 0x25, 0xCC, 0x85, 0x55, 0xBF, 0x0D, 0xEE, 0x2C, 0xEC, 0xBE, 0xE4, 0xEA, 0xAB, 0x31, 0x7C, 0xFF, 0xC9, 0x7B, 0x02, 0xF0, 0xF9, 0x8C, 0x5A, 0x48, 0x53, 0x4E, 0xCD, 0x96, 0xF1, 0x0C, 0x12, 0xA4, 0x58, 0xDE, 0x3A, 0xD1, 0x53, 0xE8, 0x91, 0xCD, 0x59, 0x26, 0xE1, 0x2E, 0x3F, 0x94, 0x1A, 0x3A, 0x4A, 0x56, 0x22, 0x34, 0xFA, 0x1E, 0x8C, 0x6C, 0x26, 0xD7, 0x49, 0xE5, 0xE0, 0xDF, 0xE7, 0x0E, 0x3B, 0xAA, 0x42, 0x3E, 0x13, 0xEF, 0x73, 0xC6, 0xDD, 0xF3, 0x15, 0x2C, 0xB8, 0x19, 0x46, 0xEF, 0x59, 0xF2, 0x01, 0xE7, 0x7C, 0xB1, 0x9A, 0xAA, 0x43, 0xE1, 0xA7, 0x27, 0xE8, 0x2C, 0x50, 0xDE, 0xBD, 0xE7, 0x08, 0x4C, 0x8A, 0xC9, 0xA4, 0xA0, 0x15, 0xD5, 0x56, 0xE5, 0xF7, 0x0B, 0x4F, 0x00, 0xC3, 0x87, 0x21, 0xB5, 0xA0, 0x4C, 0x88, 0x8B, 0x90, 0xB7, 0xB1, 0xC8, 0xD6, 0x83, 0x69, 0x49, 0x73, 0xF3, 0x29, 0x60, 0xF6, 0x2E, 0x03, 0x0C, 0x6D, 0xC9, 0xAA, 0x36, 0xEB, 0x54, 0xA2, 0x59, 0x1B, 0x2A, 0x49, 0xF1, 0xD5, 0xFA, 0xF3, 0x65, 0x02, 0xC6, 0xD4, 0x67, 0x4B, 0x7E, 0xD8, 0xCD, 0xF0, 0x81, 0x3B, 0xE2, 0xAC, 0x83, 0x29, 0x72, 0x42, 0x52, 0x2A, 0x19, 0x7B, 0x51, 0xF6, 0x48, 0x91, 0x47, 0x8F, 0x7F, 0xE7, 0x80, 0xBB, 0xB0, 0xF2, 0xBD, 0xE7, 0xE7, 0x29, 0x77, 0x8E, 0xD2, 0x79, 0xD0, 0x3D, 0x5C, 0x32, 0x5D, 0x02, 0x03, 0x95, 0x22, 0xF5, 0x74, 0x19, 0x4B, 0xC7, 0xAB, 0x61, 0xB0, 0xA0, 0xC6, 0x9C, 0x4A, 0x57, 0x36, 0x59, 0x49, 0xB6, 0xF1, 0x82, 0x2B, 0x7D, 0x4A, 0x0D, 0xE5, 0xC7, 0xA5, 0xB8, 0x76, 0x7A, 0xDD, 0xB1, 0x91, 0xF1, 0x01, 0x7A, 0xD7, 0xA1, 0x96, 0x05, 0x9A, 0xA6, 0x77, 0x9E, 0x8B, 0x60, 0xAC, 0xE5, 0x83, 0x9E, 0x61, 0xDA, 0xE2, 0x6C, 0x74, 0x62, 0xF1, 0xC3, 0xA6, 0x96, 0x6C, 0x32, 0x9A, 0x7D, 0xA5, 0xA5, 0x16, 0x5C, 0xEA, 0x0A, 0x9F, 0xA0, 0xFE, 0x46, 0x8C, 0x36, 0x99, 0xD6, 0xF6, 0xF5, 0x25, 0x48, 0x09, 0x4C, 0x7A, 0x5F, 0xB9, 0x0B, 0xA3, 0x1F, 0x64, 0x64, 0xEB, 0xFC, 0xC5, 0x80, 0x39, 0x8E, 0x4F, 0x8A, 0x45, 0x41, 0xE4, 0x9D, 0x3A, 0xA3, 0x55, 0xED, 0x81, 0x29, 0xA8, 0x42, 0xAB, 0x30, 0xE7, 0x17, 0xFC, 0xF4, 0x5E, 0x7B, 0x13, 0x22, 0xDD, 0x47, 0xF5, 0x0D, 0x7E, 0x40, 0x6D, 0x97, 0x01, 0x4B, 0x4D, 0xE5, 0xE7, 0x52, 0x6E, 0x1E, 0xC4, 0x94, 0x8B, 0x3F, 0x2D, 0x79, 0x8B, 0x6C, 0x70, 0x5B, 0xA3, 0xD0, 0xD4, 0xC5, 0x0C, 0x87, 0x2F, 0xA3, 0x8A, 0xC0, 0x17, 0x59, 0x87, 0x95, 0xED, 0x30, 0xC9, 0x7B, 0x85, 0x83, 0xBC, 0xA9, 0xCF, 0x0F, 0xB1, 0xA9, 0xCB, 0xBD, 0x7E, 0x27, 0x75, 0x06, 0x4C, 0x00, 0x0D, 0x76, 0x92, 0x64, 0xC2, 0x25, 0x99, 0x9D, 0x68, 0x5B, 0xC6, 0xD7, 0x06, 0xF1, 0x6B, 0x67, 0x85, 0x84, 0xF1, 0x1E, 0x01, 0x2B, 0xDF, 0x96, 0x6B, 0x4A, 0xB5, 0x67, 0x45, 0x18, 0x8D, 0x7C, 0x50, 0xFA, 0x8E, 0xBA, 0x75, 0x57, 0x48, 0x92, 0x80, 0x43, 0x89, 0xAE, 0x35, 0xAA, 0x0D, 0x25, 0xA9, 0xE6, 0x75, 0x81, 0x53, 0x38, 0x74, 0xE5, 0x93, 0x55, 0xD9, 0x16, 0xB5, 0x99, 0x1B, 0xB6, 0x9C, 0x52, 0xBE, 0xF5, 0x61, 0x23, 0xF7, 0xFC, 0x42, 0x22, 0x6E, 0x86, 0xFB, 0x46, 0x9A, 0xE9, 0x61, 0x12, 0x64, 0x22, 0xFC, 0x04, 0x9D, 0x57, 0x88, 0xC9, 0xDC, 0x9A, 0x76, 0xC9, 0x78, 0x2A, 0xDD, 0x17, 0xB3, 0x13, 0xB1, 0x98, 0xD9, 0x1F, 0xBA, 0xB7, 0xA6, 0x17, 0x16, 0x07, 0x83, 0x69, 0x13, 0x5D, 0x52, 0xDC, 0x6C, 0x67, 0x86, 0xFC, 0xB5, 0xBE, 0x90, 0x85, 0xB6, 0x39, 0x66, 0x9D, 0x87, 0xC2, 0xF0, 0x45, 0x79, 0x8C, 0x78, 0xE9, 0xBE, 0x72, 0xC5, 0x5D, 0xF9, 0xEF, 0x70, 0xD1, 0x85, 0x49, 0x44, 0xEE, 0x66, 0x9A, 0xE9, 0x30, 0xF8, 0x49, 0x79, 0x9F, 0x8E, 0xE3, 0xBD, 0x3E, 0x39, 0x03, 0x0E, 0x9E, 0x55, 0x64, 0xDD, 0x51, 0x9A, 0x92, 0xCE, 0xB1, 0x29, 0x05, 0x38, 0x3D, 0x0A, 0x48, 0x44, 0x3F, 0x3F, 0x8B, 0xAE, 0xDD, 0x95, 0x52, 0x31, 0x5A, 0xCE, 0xA4, 0x59, 0xE0, 0x63, 0x68, 0x5C, 0xB6, 0xD9, 0x55, 0x8E, 0x00, 0xE9, 0xFB, 0xED, 0x04, 0x68, 0xEF, 0x5D, 0x07, 0x5F, 0xEB, 0xA6, 0x46, 0x71, 0xCA, 0x11, 0x3F, 0x63, 0x0F, 0x5E, 0x0B, 0xA0, 0x57, 0xBD, 0x54, 0x46, 0xA1, 0xD0, 0xC6, 0x77, 0x98, 0x12, 0x14, 0x00, 0x52, 0xBB, 0x9D, 0xCD, 0xE6, 0x58, 0x03, 0x5A, 0xBE, 0xFB, 0x90, 0x25, 0xC2, 0xE6, 0xBB, 0x19, 0x3D, 0xA6, 0x78, 0xC1, 0xA6, 0x03, 0xA6, 0x4A, 0x2A, 0x06, 0x7D, 0x11, 0x0D, 0x5F, 0x91, 0x4C, 0x66, 0xB9, 0x5F, 0x9E, 0xD1, 0x8A, 0xCE, 0xD0, 0x12, 0x6A, 0x14, 0x89, 0xE3, 0x19, 0xE9, 0x54, 0xE5, 0x25, 0x84, 0x0D, 0x10, 0x00, 0x7B, 0x51, 0x08, 0xF6, 0xCD, 0x7C, 0xF4, 0x58, 0xEC, 0x5D, 0xBC, 0x58, 0xD5, 0x33, 0xC4, 0x8B, 0x2F, 0x60, 0xB3, 0xB7, 0x9D, 0x7D, 0x1D, 0xB9, 0x7D, 0xC2, 0xE7, 0x13, 0x65, 0xAD, 0x9D, 0xB4, 0x41, 0x97, 0x77, 0x9F, 0x1B, 0x9D, 0x01, 0x30, 0x50, 0x40, 0x27, 0x7E, 0x81, 0x28, 0x41, 0x50, 0x84, 0x09, 0x99, 0x80, 0x2E, 0x8F, 0xAE, 0x28, 0x52, 0xF2, 0xEB, 0x1B, 0x4F, 0x9F, 0xCB, 0xA7, 0xB9, 0x24, 0x86, 0x5D, 0xA2, 0xDC, 0x6E, 0xA9, 0x93, 0x3C, 0xF8, 0x89, 0xB1, 0xA1, 0x1C, 0x9E, 0x0F, 0x2A, 0xC9, 0x9F, 0xB8, 0xDB, 0xD0, 0x80, 0x14, 0xBC, 0xFE, 0x81, 0xAF, 0x75, 0xFF, 0x72, 0x87, 0x53, 0x54, 0x2E, 0x3B, 0x72, 0x58, 0x88, 0xA9, 0x71, 0x2A, 0x6D, 0x66, 0x07, 0xFA, 0xC6, 0x67, 0x34, 0x14, 0x4F, 0x48, 0x88, 0x97, 0x26, 0x6B, 0x88, 0xFA, 0x42, 0x06, 0x8F, 0xC3, 0x61, 0x28, 0x92, 0x65, 0x48, 0x52, 0x93, 0xC0, 0xC0, 0x32, 0x07, 0xCD, 0x30, 0x84, 0x65, 0x1C, 0x48, 0xB2, 0x2F, 0x89, 0x69, 0x3A, 0xB5, 0xBE, 0xCB, 0x5E, 0xE7, 0xBB, 0x1E, 0x79, 0x4B, 0xA2, 0xF0, 0x51, 0xE3, 0x66, 0x7E, 0xFA, 0x71, 0xD4, 0xDE, 0x88, 0x0A, 0x4D, 0xDC, 0xB2, 0x99, 0x35, 0x2E, 0xB2, 0xEA, 0x1D, 0xBD, 0xB8, 0x71, 0x2C, 0x89, 0x6B, 0x59, 0xE5, 0x19, 0xF9, 0xE9, 0xAB, 0xD4, 0x64, 0x8D, 0x8F, 0x18, 0xD5, 0x4B, 0xC6, 0x72, 0x38, 0x28, 0xC1, 0x04, 0xF6, 0x0C, 0x0B, 0x10, 0x0C, 0x7A, 0x7A, 0x8B, 0xFA, 0x1E, 0xCE, 0x57, 0x24, 0xDA, 0x50, 0xA5, 0x37, 0xCC, 0xE0, 0x55, 0xC5, 0x4D, 0x7D, 0x76, 0x46, 0x0F, 0xC9, 0x1D, 0xC0, 0x7A, 0xA2, 0x79, 0x27, 0xAF, 0xA2, 0xDD, 0xF6, 0x8C, 0x77, 0xAA, 0xE3, 0x4D, 0x0A, 0x79, 0xDF, 0x7E, 0x49, 0xA0, 0xBC, 0xA5, 0x6F, 0xC7, 0x66, 0xE4, 0x17, 0xF3, 0xFA, 0x72, 0xA9, 0xC5, 0xD1, 0xF3, 0x5B, 0x9E, 0x59, 0x34, 0x8A, 0x17, 0xF2, 0x79, 0x87, 0xBD, 0x9D, 0xCF, 0x6A, 0x5B, 0x05, 0x24, 0x73, 0x51, 0x5C, 0x75, 0xC7, 0xE6, 0x00, 0xA9, 0xF0, 0x6A, 0x40, 0x0C, 0xAE, 0xAD, 0x34, 0x76, 0x87, 0x2A, 0x43, 0x51, 0x2C, 0xF9, 0xC4, 0x38, 0x29, 0x9B, 0xD5, 0xC7, 0x44, 0x0A, 0xE4, 0x46, 0x65, 0x5C, 0x4C, 0xBB, 0x95, 0x11, 0xE6, 0x2B, 0x0D, 0x31, 0x8A, 0x21, 0x6C, 0xDA, 0x00, 0x29, 0xBC, 0x07, 0xAC, 0x5B, 0x7A, 0x92, 0x83, 0x05, 0xFC, 0x32, 0x8E, 0x29, 0xEE, 0xE3, 0xB6, 0x32, 0xFE, 0x36, 0x50, 0x83, 0xF7, 0x19, 0x8D, 0x89, 0xBA, 0x20, 0xED, 0xCA, 0x7B, 0xC8, 0x41, 0xF3, 0x4B, 0xA0, 0xC0, 0x42, 0xCA, 0x22, 0xF9, 0xA1, 0x66, 0xD3, 0x8A, 0xCC, 0x62, 0xFE, 0xF2, 0xBC, 0xD0, 0xCE, 0x11, 0xB4, 0x24, 0x53, 0x2F, 0xDF, 0x23, 0x04, 0xBD, 0xD0, 0x44, 0x1B, 0x00, 0xD8, 0xB1, 0x39, 0x0C, 0x28, 0xF7, 0xD7, 0x7C, 0xDC, 0x2B, 0x6A, 0x63, 0xE5, 0x0E, 0x0D, 0x8C, 0x00, 0x8E, 0x20, 0xD8, 0xE2, 0x52, 0xCA, 0xFE, 0xA4, 0xDE, 0x32, 0xDF, 0xBE, 0x2A, 0xB9, 0xE6, 0x1B, 0x3E, 0xE3, 0x8C, 0x78, 0xB8, 0x19, 0xF7, 0xA2, 0x7E, 0xBE, 0xAC, 0xD1, 0xDF, 0x4B, 0x1D, 0x7A, 0xE9, 0x03, 0xE5, 0xB5, 0x17, 0x2E, 0x88, 0x8E, 0x94, 0x86, 0xC2, 0xCD, 0xAA, 0xEA, 0xD5, 0xAF, 0xEE, 0xF0, 0x82, 0x7C, 0x77, 0xDF, 0x7E, 0xD8, 0x6E, 0x25, 0xF5, 0x9D, 0xAB, 0x09, 0x6A, 0x10, 0xF2, 0x6B, 0x61, 0xF6, 0x8A, 0xD3, 0xDA, 0xB8, 0xD9, 0x4E, 0xDE, 0xB8, 0xF4, 0xA5, 0x8D, 0x66, 0x78, 0x52, 0x07, 0x81, 0xE0, 0x98, 0x54, 0xA7, 0x6B, 0xEC, 0x91, 0x3C, 0x99, 0xA5, 0xFE, 0xEE, 0xB8, 0x63, 0x1A, 0xB5, 0x16, 0xC5, 0xC0, 0xBD, 0x06, 0xEE, 0xE3, 0x12, 0x16, 0x01, 0xF4, 0xAF, 0xBF, 0x8C, 0xFB, 0xD7, 0xD9, 0x8D, 0xDF, 0x73, 0x1B, 0x3A, 0xE7, 0xFF, 0xF2, 0xAF, 0x34, 0xFF, 0x7F, 0x5F, 0x61, 0xFD, 0x6F, 0xC9, 0x5E, 0xFC, 0x9A, 0xFE, 0xD5, 0x9F, 0xF7, 0x66, 0x28, 0x7E, 0x05, 0xD3, 0xBF, 0xFE, 0xF9, 0xC7, 0x3F, 0xA7, 0x2E, 0x8E, 0xDF, 0x2B, 0xFF, 0x6D, 0x99, 0x8B, 0x7F, 0x95, 0xB5, 0xF8, 0x6F, 0x65, 0x32, 0xD2, 0xBF, 0x8A, 0x6B, 0x51, 0xFC, 0x90, 0x8B, 0x64, 0xFE, 0xBB, 0xA6, 0xCA, 0x6F, 0x7D, 0xFD, 0xAD, 0xFE, 0x07, 0xD2, 0x24, 0xE9, 0x5F, 0xF5, 0x66, 0x6C, 0x86, 0x63, 0xF8, 0x6F, 0xD9, 0x1F, 0xFE, 0xB8, 0xF4, 0x0F, 0x37, 0xA1, 0xF0, 0xE2, 0x8F, 0xE0, 0x8F, 0x8C, 0xCE, 0xDF, 0xB5, 0xD0, 0xE4, 0xE5, 0x3F, 0x9E, 0xEA, 0xF9, 0x36, 0x30, 0xEE, 0xC5, 0x3A, 0x26, 0xFD, 0x0F, 0xAF, 0x18, 0xE6, 0x62, 0x4D, 0xF6, 0x63, 0xFD, 0xFB, 0x69, 0x69, 0xFE, 0x76, 0xCB, 0x57, 0xDA, 0xFC, 0x5B, 0x07, 0xF3, 0x4F, 0x29, 0xA4, 0xFF, 0x41, 0x99, 0x93, 0x1F, 0x7F, 0xFB, 0xBC, 0x93, 0x44, 0xFF, 0x33, 0x84, 0xFF, 0xFC, 0xA4, 0xF3, 0xAF, 0xFF, 0x37, 0xC9, 0x9B, 0xFF, 0x2E, 0xAD, 0xC0, 0x08, 0x8E, 0xFE, 0x67, 0xF4, 0x5F, 0xB6, 0xF3, 0xBF, 0xF2, 0x48, 0xFF, 0x58, 0x1E, 0x29, 0x67, 0xFF, 0xAF, 0x3C, 0xD2, 0x4C, 0x77, 0xDF, 0x38, 0x2D, 0x67, 0x19, 0x78, 0x02, 0x65, 0xB6, 0x93, 0x48, 0x84, 0x86, 0x41, 0x9C, 0xD1, 0xE6, 0x27, 0x16, 0xCB, 0x42, 0x45, 0x76, 0x5D, 0x6C, 0x44, 0x9C, 0x7A, 0x87, 0x9B, 0xE4, 0xF6, 0x5D, 0xDD, 0x54, 0x62, 0xFB, 0x8E, 0x93, 0x56, 0x69, 0x24, 0x59, 0x42, 0x5C, 0xE6, 0xE8, 0xC4, 0xDD, 0x1D, 0x62, 0xE7, 0xA5, 0x3A, 0xF1, 0xA8, 0xE9, 0xAE, 0x27, 0x08, 0xDB, 0xA0, 0x48, 0xBE, 0xD8, 0xAA, 0x05, 0xD7, 0x71, 0x9E, 0x9E, 0xE7, 0x42, 0xC4, 0x08, 0x22, 0x23, 0xA1, 0x71, 0x01, 0x00, 0xA8, 0x96, 0x3F, 0xE5, 0x89, 0x7C, 0x56, 0xEE, 0xDB, 0x4E, 0x8A, 0x8E, 0xE3, 0x79, 0x72, 0x32, 0x4D, 0x5A, 0x8F, 0x4E, 0x9A, 0xA3, 0x59, 0xA2, 0xC0, 0x83, 0x96, 0x38, 0x7A, 0x7E, 0x59, 0xCB, 0x57, 0x29, 0x7F, 0x83, 0xD0, 0x97, 0x95, 0xBA, 0x2F, 0x7F, 0xF1, 0x01, 0x83, 0x69, 0x9C, 0x02, 0xD9, 0x5D, 0x97, 0x96, 0x0F, 0xFB, 0xD6, 0x1A, 0x81, 0x52, 0x16, 0x1F, 0xED, 0x5F, 0x6E, 0x16, 0xB7, 0x80, 0x08, 0xB9, 0x43, 0xD5, 0x7E, 0x82, 0x2E, 0x8D, 0x06, 0x84, 0xB6, 0x6D, 0xCC, 0x77, 0xE1, 0x57, 0xCD, 0xF3, 0xCD, 0x10, 0x67, 0xEE, 0x64, 0x3C, 0x89, 0x17, 0x58, 0x8D, 0x7E, 0x89, 0x11, 0xA3, 0x73, 0x9C, 0x2B, 0xF7, 0x2B, 0x09, 0x4C, 0xD1, 0xDC, 0x4E, 0x4C, 0x3E, 0xE9, 0x27, 0x02, 0x85, 0xAF, 0xF4, 0x2B, 0x77, 0x00, 0x63, 0x0B, 0x68, 0xCB, 0x80, 0x10, 0x3B, 0x58, 0x6F, 0xCD, 0x0B, 0x40, 0x76, 0xBD, 0xEB, 0xDC, 0x4F, 0xE2, 0x57, 0xC4, 0xAD, 0xD7, 0x1A, 0x30, 0x97, 0x00, 0x27, 0xD1, 0x95, 0x42, 0xB5, 0x3D, 0x75, 0x15, 0x69, 0x7F, 0x45, 0xDA, 0x7D, 0x6B, 0x11, 0x0E, 0x14, 0xAB, 0xB6, 0x3D, 0x82, 0xBC, 0xB3, 0x80, 0x33, 0x5C, 0xD2, 0x46, 0x7C, 0xC4, 0x36, 0x53, 0xB3, 0x57, 0x24, 0x66, 0x31, 0xAE, 0x16, 0x72, 0x58, 0xC9, 0x5E, 0x63, 0xE7, 0x8B, 0xA7, 0xA4, 0xA9, 0xC4, 0x1B, 0x14, 0x68, 0xC2, 0x83, 0x59, 0x2C, 0x67, 0x03, 0xBF, 0xF9, 0x28, 0x4F, 0x9A, 0xCF, 0xA0, 0x50, 0xB7, 0x4C, 0xB4, 0x10, 0xD2, 0xF6, 0x98, 0x41, 0x30, 0xF2, 0x07, 0x7A, 0xB5, 0xB1, 0xE7, 0x89, 0xA5, 0xFB, 0x59, 0x06, 0xF7, 0x95, 0x6E, 0x14, 0x6A, 0x3D, 0x13, 0x33, 0xAC, 0x5E, 0xC4, 0x3D, 0x18, 0x17, 0x57, 0x1C, 0x98, 0x3E, 0xE7, 0xD4, 0x04, 0x97, 0x41, 0xF8, 0x1C, 0x13, 0xE2, 0x0B, 0xFC, 0xEE, 0xF8, 0x3D, 0x79, 0x6D, 0x1B, 0x88, 0x9A, 0x09, 0xAE, 0x03, 0x4C, 0xCE, 0xC7, 0xDB, 0x44, 0x5F, 0x1A, 0xCA, 0x0C, 0x51, 0xF1, 0xB2, 0x62, 0xE3, 0xAC, 0x9E, 0xC9, 0xB6, 0x7D, 0xE2, 0xA6, 0xC7, 0xBD, 0x7E, 0xF5, 0x00, 0xD1, 0xCE, 0xB8, 0x06, 0x9B, 0xD4, 0xED, 0x38, 0x95, 0x51, 0x0C, 0x91, 0x17, 0xDB, 0xC3, 0x9B, 0xEB, 0x71, 0x79, 0xBC, 0x6A, 0x41, 0x09, 0x14, 0x89, 0x2E, 0x82, 0xB1, 0x10, 0x31, 0x2F, 0xB1, 0x00, 0x43, 0x32, 0xA8, 0xF3, 0x86, 0x65, 0x23, 0xF4, 0x1A, 0x4B, 0xF1, 0x2E, 0x34, 0xBD, 0x16, 0x8F, 0xB3, 0xCA, 0x18, 0x62, 0x88, 0xD1, 0x91, 0xCC, 0x5D, 0xCC, 0x3E, 0xDA, 0xB8, 0xEC, 0xA3, 0x39, 0xAC, 0x67, 0x41, 0x3D, 0x93, 0xD8, 0xCB, 0x83, 0xED, 0x92, 0xDC, 0x83, 0x62, 0xEF, 0x9A, 0x3F, 0x26, 0x95, 0x5C, 0x44, 0xBD, 0x58, 0x25, 0x34, 0x90, 0x22, 0x00, 0x8A, 0x24, 0x89, 0x81, 0x89, 0xB8, 0xD0, 0xB7, 0x0A, 0xC4, 0x72, 0x5D, 0x0E, 0x44, 0xBB, 0x07, 0xAB, 0x81, 0x15, 0x55, 0x60, 0x3B, 0xD1, 0xA4, 0xB3, 0x66, 0xAD, 0xC8, 0x63, 0x8C, 0x0F, 0x56, 0xB9, 0x98, 0x37, 0x16, 0xAB, 0x23, 0xFE, 0x83, 0x7F, 0x32, 0x61, 0xEA, 0x2D, 0x20, 0x92, 0xE9, 0x7C, 0x83, 0x89, 0x9C, 0x90, 0x41, 0xBA, 0xE2, 0x5B, 0xF6, 0x24, 0x2C, 0x68, 0xB2, 0x08, 0xE9, 0x02, 0x30, 0x3D, 0xAC, 0x7C, 0xDD, 0x1C, 0x59, 0x6F, 0x62, 0x55, 0x05, 0xFE, 0xE0, 0xD5, 0xE4, 0xD6, 0x4D, 0x3A, 0x29, 0x22, 0x0B, 0x36, 0xB6, 0xF3, 0xFE, 0xE4, 0x48, 0x4B, 0xBF, 0xE2, 0x2B, 0x8D, 0xD1, 0x14, 0x77, 0xE7, 0x4C, 0x22, 0xAE, 0xB9, 0xEB, 0xC1, 0x5A, 0x63, 0xA8, 0x07, 0x44, 0x3A, 0xD6, 0x4A, 0xA6, 0x6D, 0xD3, 0xDF, 0x52, 0x6F, 0xA9, 0x65, 0x97, 0x22, 0x96, 0x23, 0xF5, 0x19, 0xD5, 0x15, 0xB2, 0x2B, 0xBE, 0xE2, 0xB9, 0xC2, 0x20, 0xF0, 0x7A, 0x59, 0x75, 0xA0, 0xFB, 0x0A, 0x39, 0x04, 0xF0, 0x47, 0x66, 0x5D, 0xA0, 0x38, 0x45, 0xF1, 0x10, 0xE7, 0x05, 0x46, 0x37, 0xF6, 0xA0, 0x4E, 0x4F, 0xE3, 0xC0, 0x8F, 0xD6, 0xE7, 0x14, 0xC9, 0xC4, 0x44, 0xAD, 0x9D, 0x06, 0x8D, 0x30, 0x70, 0x60, 0x82, 0xD1, 0x52, 0xE9, 0xE6, 0x6D, 0x73, 0x05, 0xCA, 0xB2, 0x2F, 0xFC, 0x68, 0x2F, 0x31, 0x9C, 0xF2, 0x6B, 0xC6, 0xEB, 0xA1, 0x74, 0x52, 0xCC, 0x9D, 0xC8, 0xFE, 0x2B, 0x6E, 0xCE, 0xA5, 0x7D, 0x14, 0x55, 0xEE, 0x70, 0x19, 0x5C, 0x89, 0x09, 0x5D, 0xE4, 0xB2, 0xDD, 0xFC, 0x18, 0x19, 0xA6, 0x06, 0xDA, 0x9F, 0x35, 0xF7, 0x03, 0x7C, 0x80, 0x3E, 0x4F, 0x39, 0x15, 0x05, 0x47, 0x0D, 0x94, 0xF6, 0xDA, 0x43, 0xFD, 0xCB, 0x4A, 0x63, 0x60, 0x9D, 0xA4, 0xFB, 0x7B, 0x3B, 0xF1, 0xDC, 0x88, 0xBA, 0xF1, 0xDB, 0x7B, 0xA6, 0xE1, 0x95, 0xDF, 0x47, 0x5E, 0x30, 0xA4, 0x2D, 0xEB, 0xE1, 0x33, 0x32, 0x0C, 0x2C, 0xC2, 0x1C, 0x9C, 0x34, 0x05, 0xAA, 0xE9, 0x8E, 0x6C, 0x85, 0xB9, 0x70, 0x99, 0x97, 0xC4, 0x79, 0x51, 0x4B, 0xF3, 0x68, 0x3E, 0xE5, 0xBD, 0xAE, 0x45, 0x51, 0xE3, 0xB8, 0xBD, 0x5E, 0xFC, 0x06, 0x75, 0x3E, 0xA0, 0xED, 0x3B, 0xC0, 0xAE, 0x3C, 0x1E, 0x35, 0xC8, 0xE8, 0x24, 0x1C, 0xB1, 0x82, 0xF3, 0x21, 0x33, 0x72, 0x78, 0x29, 0x1F, 0x75, 0xD5, 0x5E, 0x2E, 0xD8, 0xBF, 0x9A, 0x61, 0x0C, 0x83, 0x8C, 0xE1, 0x60, 0x78, 0xE4, 0x2E, 0x0A, 0x7B, 0x91, 0x47, 0x26, 0xB9, 0x69, 0x6F, 0x48, 0x65, 0x48, 0x05, 0x4B, 0xB6, 0x59, 0x53, 0x76, 0xDB, 0xA1, 0x20, 0xA0, 0x3E, 0x20, 0x2F, 0x13, 0xAF, 0xF4, 0xEF, 0xEC, 0xBD, 0x2A, 0x6A, 0x6B, 0xEF, 0x1A, 0x02, 0x01, 0xAF, 0xF7, 0x29, 0xC1, 0x69, 0x2A, 0x6C, 0xEA, 0x49, 0x9F, 0x91, 0xA2, 0x94, 0x39, 0xDD, 0x8A, 0xD0, 0x81, 0xC5, 0x0D, 0xDF, 0x6E, 0xAD, 0x9F, 0x25, 0xC4, 0x53, 0x74, 0xD9, 0x47, 0x90, 0xEB, 0x4D, 0x26, 0xB3, 0x59, 0xAE, 0x02, 0xBD, 0xC7, 0x35, 0x7E, 0xD3, 0xD0, 0x91, 0x95, 0xEF, 0x85, 0xDB, 0x59, 0x09, 0x75, 0x2F, 0x8F, 0x6C, 0xF3, 0x2A, 0xE8, 0x38, 0x98, 0xB6, 0xAC, 0x6D, 0x3D, 0x8E, 0xA5, 0xA0, 0x29, 0x36, 0x56, 0xEA, 0x70, 0x30, 0x58, 0xA3, 0xDD, 0x4C, 0x1A, 0x84, 0x9F, 0xCA, 0xF9, 0x3C, 0x10, 0x40, 0xCB, 0x11, 0xAD, 0xC1, 0x9D, 0x5B, 0x3D, 0xFA, 0x0E, 0x21, 0xF2, 0xDB, 0x44, 0x02, 0x4F, 0x2C, 0x18, 0xF5, 0xC3, 0x9B, 0x1D, 0x94, 0xC3, 0x95, 0x54, 0x97, 0xC7, 0xAB, 0x65, 0x7A, 0x00, 0x75, 0xA8, 0xE5, 0x19, 0x6C, 0x5B, 0x0F, 0x09, 0x3A, 0x5A, 0x4C, 0xA1, 0xA8, 0x25, 0xC0, 0x46, 0x72, 0x07, 0xE0, 0xBD, 0xDA, 0x5A, 0x95, 0x00, 0xE9, 0x57, 0xA9, 0x14, 0x2C, 0x03, 0x79, 0xB2, 0x8D, 0x42, 0xF2, 0x37, 0x44, 0x6C, 0xB3, 0xA2, 0x62, 0x27, 0x31, 0xE0, 0xBD, 0x3F, 0x69, 0x88, 0x8A, 0x27, 0xD9, 0x70, 0xE7, 0x1A, 0xE8, 0x7D, 0x1E, 0x23, 0x1C, 0x40, 0x56, 0x3D, 0x22, 0xCA, 0x87, 0xBE, 0x62, 0x69, 0xDF, 0x1B, 0x3D, 0xB3, 0x7A, 0xF4, 0x32, 0x60, 0x60, 0xEA, 0x61, 0xE9, 0xA8, 0xD4, 0x6C, 0xCD, 0xA1, 0xF5, 0x8E, 0xF3, 0x87, 0xFA, 0x1C, 0xBC, 0xD9, 0xB2, 0x7A, 0xCE, 0x04, 0x53, 0x2A, 0x3C, 0x8F, 0x65, 0xF3, 0x19, 0x11, 0xC0, 0x93, 0xD1, 0x2E, 0xA4, 0x37, 0x91, 0xB2, 0x94, 0x07, 0x8A, 0x9C, 0x02, 0x02, 0xB1, 0x0B, 0x9D, 0x42, 0x9A, 0x59, 0x9D, 0x50, 0x25, 0x09, 0x51, 0x5C, 0x04, 0xED, 0x65, 0x45, 0xCE, 0x92, 0xB0, 0xC5, 0x6D, 0xA8, 0xA5, 0x7C, 0x95, 0xBD, 0xB5, 0x90, 0xEE, 0x85, 0xF6, 0xBB, 0xF1, 0x31, 0xDC, 0x01, 0x18, 0xE3, 0xDA, 0xCB, 0xF3, 0x2B, 0xA6, 0x4D, 0x83, 0xF1, 0x90, 0x8E, 0xD9, 0x6C, 0x52, 0xD9, 0x9E, 0x18, 0xB9, 0x79, 0x2B, 0x7E, 0xAF, 0xB4, 0xAB, 0x1A, 0xA6, 0x7E, 0xB2, 0x22, 0x1B, 0xD3, 0x2D, 0x22, 0xF7, 0xC3, 0xB4, 0x3E, 0xF6, 0xF1, 0xA0, 0x23, 0x1C, 0x80, 0xB9, 0x33, 0x43, 0xEB, 0xF6, 0x5A, 0x01, 0x0D, 0x07, 0x58, 0xEA, 0x81, 0xDE, 0x8C, 0x99, 0x9B, 0xD8, 0xB5, 0x86, 0xE4, 0x8A, 0xA7, 0xE7, 0x31, 0xEC, 0x76, 0x9B, 0xC5, 0xE3, 0x55, 0x19, 0x8E, 0x01, 0x0D, 0x91, 0xEB, 0x5D, 0xE1, 0x73, 0x99, 0x56, 0x9D, 0x0B, 0x53, 0x79, 0x6D, 0xD4, 0xFD, 0xA6, 0xE6, 0x76, 0xBF, 0x97, 0xC2, 0x8A, 0x2B, 0x75, 0x43, 0x08, 0xE7, 0xE5, 0x04, 0xBD, 0xB6, 0xED, 0xD0, 0x3E, 0x3B, 0xEA, 0x4B, 0x1F, 0x4F, 0xEE, 0x9D, 0x9E, 0x66, 0x42, 0x52, 0x03, 0x83, 0x54, 0x70, 0xD2, 0x02, 0x31, 0x4D, 0x03, 0x4D, 0x9C, 0xBD, 0xDC, 0x94, 0xD8, 0xCB, 0x29, 0x0A, 0xF0, 0xDB, 0x72, 0xFA, 0xAA, 0xD6, 0x83, 0x0C, 0x17, 0x01, 0xC0, 0xB8, 0x14, 0x01, 0xDB, 0x71, 0x40, 0x50, 0x81, 0xE8, 0x62, 0x5D, 0xAB, 0xB0, 0xFD, 0xB6, 0x33, 0x19, 0x55, 0x43, 0xFB, 0x82, 0x4F, 0xDA, 0x7B, 0x78, 0xE5, 0x26, 0xDA, 0xC6, 0xCE, 0xE7, 0x7C, 0x23, 0x62, 0x47, 0x9F, 0xF9, 0xC7, 0x31, 0x39, 0xC3, 0x21, 0x5C, 0x0B, 0xB2, 0x28, 0xAE, 0x10, 0x1E, 0x0F, 0xC3, 0x8A, 0xBE, 0x13, 0x67, 0x5C, 0x81, 0x01, 0x53, 0x41, 0x26, 0x58, 0x9F, 0x3F, 0x55, 0xEE, 0xA2, 0x26, 0x6E, 0x51, 0x62, 0xFF, 0xF3, 0xCB, 0x2A, 0xD2, 0xDD, 0x66, 0x19, 0x9A, 0xF4, 0x22, 0xBD, 0xDE, 0x0A, 0xC8, 0xF6, 0x6F, 0x82, 0x9F, 0x0B, 0xD3, 0xAC, 0x26, 0xEB, 0xB9, 0xEE, 0xA8, 0x24, 0x13, 0x00, 0xAD, 0x1F, 0x9A, 0xA4, 0xFC, 0xCD, 0x02, 0x33, 0x14, 0x59, 0x18, 0xA0, 0x0D, 0x09, 0xCD, 0x78, 0xCC, 0xB2, 0x24, 0xBA, 0xE2, 0x36, 0x5D, 0x3B, 0xC0, 0x1F, 0x89, 0xDE, 0xD2, 0x15, 0x2F, 0x19, 0x0D, 0x63, 0x11, 0x03, 0x13, 0x38, 0x9E, 0x44, 0xF0, 0x11, 0x39, 0x5D, 0xF6, 0xA1, 0xEC, 0xE2, 0xB3, 0x77, 0x48, 0x31, 0x58, 0x7E, 0xDE, 0x3B, 0x57, 0x80, 0xA1, 0xD4, 0x9B, 0x10, 0xE7, 0x49, 0xD3, 0x33, 0x78, 0x03, 0xBD, 0x98, 0x42, 0xEB, 0x01, 0xF5, 0x13, 0x7B, 0xB5, 0x98, 0x4C, 0x04, 0xEC, 0x41, 0x6D, 0x4A, 0xF3, 0x34, 0x10, 0xC0, 0x9D, 0xCB, 0x7D, 0xCE, 0xBF, 0x8B, 0xD1, 0xB0, 0x7A, 0xB2, 0x70, 0x37, 0x83, 0x91, 0xF0, 0x7D, 0x7A, 0x65, 0x27, 0xFA, 0xBC, 0x8A, 0x3E, 0x3A, 0xD6, 0x31, 0xE7, 0x8E, 0x15, 0x4D, 0x78, 0xB8, 0x3F, 0xB9, 0xC9, 0x1E, 0xE1, 0x04, 0xBA, 0x09, 0xBF, 0x7E, 0xE7, 0x67, 0x87, 0x22, 0x38, 0x6C, 0xD2, 0x35, 0x2A, 0x2E, 0xB9, 0x80, 0x2D, 0xB7, 0x59, 0xB3, 0xA3, 0x6F, 0x82, 0x6D, 0xE3, 0xF2, 0x7B, 0x14, 0x4A, 0xC0, 0x46, 0x7E, 0xC9, 0x38, 0x62, 0xB5, 0x75, 0xFA, 0x64, 0x37, 0xB2, 0xA1, 0xDF, 0xA7, 0x3E, 0x00, 0x67, 0x33, 0x56, 0x8F, 0xE1, 0x7A, 0x07, 0x99, 0x78, 0x62, 0x1C, 0xE6, 0x60, 0x45, 0x44, 0x9D, 0x2B, 0x19, 0x6B, 0x32, 0x6F, 0x52, 0x84, 0x23, 0xCC, 0xD8, 0xEE, 0x6F, 0x74, 0x75, 0x82, 0x51, 0xF7, 0xE4, 0x5E, 0x60, 0xC1, 0xB3, 0x45, 0x99, 0xE5, 0x2B, 0xBB, 0x55, 0x5D, 0x7D, 0x13, 0x56, 0x85, 0xA7, 0x62, 0x33, 0xE4, 0x00, 0x5E, 0x10, 0xB5, 0xF3, 0x60, 0xF3, 0x51, 0x89, 0x5E, 0x00, 0xD4, 0x54, 0xCD, 0x46, 0xCC, 0x5B, 0xE1, 0xB5, 0x87, 0x42, 0xF3, 0xB6, 0x93, 0x5B, 0xDC, 0xBB, 0xE9, 0x74, 0x8E, 0x74, 0x35, 0x49, 0x8A, 0x51, 0x4E, 0x78, 0xA4, 0xD4, 0x70, 0x16, 0xF5, 0x5F, 0xD7, 0x40, 0x61, 0x06, 0xD8, 0x3E, 0x35, 0x5F, 0x2B, 0x48, 0xD0, 0x0F, 0x0F, 0x7C, 0x57, 0x66, 0x0C, 0x86, 0x48, 0xC0, 0x40, 0x0C, 0x82, 0xE3, 0xA1, 0x4A, 0x3B, 0x87, 0xC9, 0xEF, 0x29, 0xBF, 0xD6, 0xC6, 0x92, 0x9A, 0x91, 0x7A, 0x3F, 0xCD, 0x22, 0x7C, 0xB1, 0xA8, 0x61, 0xCC, 0xE6, 0x73, 0x23, 0x38, 0x38, 0x2B, 0x87, 0x19, 0xC9, 0xE5, 0xD0, 0x14, 0x4C, 0xCA, 0x38, 0x5A, 0xF1, 0x01, 0x2B, 0x27, 0x12, 0xFB, 0x97, 0x96, 0x62, 0x13, 0xCE, 0x92, 0x6D, 0x61, 0x0B, 0xDD, 0x62, 0xC1, 0x40, 0x75, 0x24, 0xD2, 0x9B, 0x5D, 0x9F, 0xD6, 0xE8, 0x59, 0xFA, 0xC3, 0x6C, 0xF3, 0xCC, 0x97, 0xA2, 0x0E, 0xF1, 0x5F, 0x11, 0xF8, 0x86, 0x84, 0x42, 0x0D, 0xEC, 0x6E, 0x9D, 0xBD, 0x5C, 0xD0, 0xB7, 0x97, 0x4E, 0x4D, 0x35, 0x6F, 0x88, 0x6A, 0x26, 0x79, 0x65, 0x3D, 0xAB, 0xCA, 0x7B, 0x50, 0x55, 0x85, 0xD5, 0x6E, 0xC4, 0x11, 0xAE, 0xF4, 0xA8, 0x2C, 0xDC, 0x4A, 0x3F, 0xD1, 0xB4, 0x9A, 0x2E, 0xDB, 0xBA, 0x87, 0x46, 0x93, 0x3D, 0xE5, 0x3B, 0x39, 0x17, 0xA2, 0x58, 0xA5, 0x3D, 0xAD, 0xFA, 0x5D, 0x89, 0x9C, 0x07, 0x0F, 0x9E, 0x92, 0x4F, 0x44, 0xFD, 0xF0, 0x64, 0x4B, 0x02, 0x61, 0x2B, 0x1D, 0x62, 0x29, 0x6B, 0x8E, 0x3C, 0x3C, 0xC5, 0x29, 0x68, 0x6B, 0xAB, 0x87, 0xEF, 0x7B, 0xCC, 0xE2, 0xE4, 0xB3, 0x17, 0xA5, 0x45, 0x44, 0x40, 0x39, 0x52, 0xA7, 0xEF, 0xBE, 0x84, 0x26, 0x50, 0x7B, 0xAE, 0xAD, 0x87, 0x93, 0x62, 0xDD, 0x2D, 0x6F, 0x91, 0xCC, 0x71, 0x20, 0xF3, 0xFA, 0x37, 0x6B, 0xCF, 0xB0, 0x11, 0x9B, 0xFF, 0x49, 0xC4, 0xA7, 0x62, 0xFD, 0xBD, 0xC2, 0x99, 0xFF, 0xBB, 0x8A, 0x4E, 0xA3, 0xD8, 0xAF, 0x69, 0xED, 0xFE, 0xAE, 0x91, 0xF1, 0x8F, 0xDA, 0x7F, 0x48, 0xAD, 0x79, 0xF7, 0xFC, 0xF7, 0xEA, 0xEC, 0x8F, 0x3F, 0x28, 0xFE, 0x07, 0x6C, 0xBA, 0x5F, 0xE7, 0x26, 0xFD, 0xDF, 0x59, 0xDD, 0x7E, 0xAF, 0xFC, 0xC7, 0xD4, 0x31, 0xC3, 0xFD, 0x60, 0xF2, 0x7C, 0x2D, 0xB6, 0xED, 0xEF, 0xC5, 0x71, 0x92, 0x25, 0x7F, 0x5C, 0xF8, 0x9F, 0x53, 0x4E, 0xFE, 0xFB, 0xC8, 0xC7, 0xFF, 0x25, 0x16, 0xFF, 0x10, 0x8B, 0xC7, 0x4F, 0xCC, 0x48, 0x37, 0xD6, 0x3C, 0x9E, 0x16, 0xFB, 0xFF, 0x24, 0x16, 0x11, 0xE8, 0x9F, 0xC4, 0x22, 0x1C, 0xEF, 0x64, 0xC7, 0x46, 0xC1, 0x98, 0x7D, 0xBB, 0x8C, 0x83, 0x68, 0x59, 0x64, 0x00, 0x3B, 0x76, 0x9D, 0xBA, 0xF4, 0x49, 0x2F, 0x56, 0x82, 0xD0, 0x46, 0xAD, 0xD3, 0xCD, 0xD1, 0x54, 0x33, 0x8A, 0x2F, 0x4D, 0x6F, 0x85, 0x1E, 0x8C, 0x6E, 0x62, 0xC5, 0xAA, 0x7B, 0x65, 0x5F, 0x62, 0x85, 0x86, 0x77, 0xBF, 0x88, 0xC7, 0x6B, 0x11, 0xDB, 0x04, 0x78, 0x2F, 0xA3, 0x63, 0x6B, 0x8C, 0xEB, 0x85, 0xAC, 0xC1, 0x54, 0x72, 0xB4, 0xEA, 0x2E, 0xF5, 0x62, 0xDE, 0xA5, 0x64, 0xBC, 0x73, 0x24, 0x40, 0x33, 0xCE, 0x26, 0xAC, 0x77, 0x91, 0x00, 0xF1, 0x57, 0xFE, 0xA3, 0xF4, 0x61, 0x6D, 0x28, 0x98, 0x11, 0x31, 0x79, 0x14, 0xE0, 0x89, 0x94, 0xD9, 0x87, 0x11, 0x73, 0x60, 0x59, 0xD2, 0xD1, 0x2B, 0x33, 0x70, 0xA6, 0xC0, 0x11, 0x31, 0x53, 0xF0, 0x7B, 0x8E, 0x9F, 0x9C, 0xEA, 0xFB, 0xD1, 0xB9, 0xFA, 0x65, 0x7A, 0xD2, 0x76, 0x62, 0xF9, 0x21, 0xD4, 0x8C, 0xF0, 0x31, 0x24, 0xF8, 0x90, 0xC7, 0x46, 0x13, 0x5D, 0xD8, 0xBC, 0x96, 0x24, 0xDC, 0xA0, 0x0F, 0x69, 0x55, 0xAC, 0xAB, 0x7D, 0x99, 0x07, 0xE7, 0xF2, 0xDE, 0x46, 0xE4, 0x99, 0x4A, 0xDB, 0x93, 0x64, 0xE1, 0x81, 0x32, 0x27, 0xD2, 0x1A, 0x9B, 0x47, 0x66, 0xB1, 0x5A, 0x02, 0xEE, 0xA3, 0x41, 0x3F, 0x60, 0x3F, 0xE1, 0x5A, 0xE7, 0xFB, 0x00, 0x28, 0x74, 0x15, 0x44, 0x9A, 0x6D, 0x28, 0x99, 0x50, 0xC3, 0xB6, 0x97, 0xC0, 0x68, 0x57, 0x63, 0x52, 0xA4, 0xD2, 0xA5, 0xE9, 0x07, 0x81, 0x43, 0x2B, 0xFD, 0xAA, 0x56, 0xF2, 0x59, 0xFB, 0x8C, 0xF7, 0xF8, 0xDA, 0xF6, 0x64, 0xD9, 0xFA, 0xF9, 0xCA, 0x2B, 0x63, 0xAE, 0x67, 0x01, 0xB5, 0x6D, 0x7D, 0x3E, 0x9F, 0x75, 0x47, 0xC9, 0x16, 0x95, 0x53, 0xEF, 0x1E, 0x97, 0x56, 0xAE, 0xE0, 0x01, 0x04, 0x62, 0xF1, 0xFD, 0xA5, 0x1F, 0x21, 0x28, 0x65, 0x9A, 0xBE, 0x39, 0xD4, 0xC8, 0x2B, 0x86, 0x62, 0x31, 0x62, 0x63, 0x60, 0xA2, 0x1B, 0x8B, 0x06, 0x7F, 0x13, 0x78, 0x4A, 0x01, 0x9E, 0x87, 0x93, 0xC4, 0x8C, 0x43, 0x6F, 0x93, 0xC1, 0xE3, 0x0D, 0x31, 0xE4, 0x57, 0x93, 0xC8, 0x91, 0x93, 0x0B, 0x65, 0x43, 0x85, 0x9E, 0x11, 0x15, 0x19, 0x86, 0xF6, 0x02, 0x76, 0x8D, 0x72, 0xE6, 0x4F, 0xB3, 0x53, 0x9D, 0xF8, 0x71, 0x93, 0x3E, 0x16, 0x72, 0xCE, 0xF0, 0xA5, 0x13, 0x9D, 0x7E, 0x8A, 0x86, 0xE8, 0x8B, 0x1F, 0xD0, 0xB8, 0xF4, 0x5B, 0xF0, 0xDB, 0x81, 0x1F, 0x56, 0xA3, 0xAF, 0xC2, 0x0C, 0xFF, 0x80, 0x82, 0x6A, 0x70, 0xF6, 0x53, 0xC9, 0x96, 0x29, 0xBD, 0x5D, 0x2E, 0x75, 0x33, 0xD9, 0x60, 0x5F, 0xA0, 0xD5, 0x22, 0xD5, 0xC6, 0xF7, 0x54, 0x55, 0x99, 0x2E, 0x44, 0x64, 0x64, 0x5D, 0x31, 0xA7, 0xC7, 0x5A, 0x71, 0x54, 0xBB, 0x27, 0x65, 0xF1, 0xDF, 0xF0, 0x4E, 0x8A, 0x13, 0x0F, 0xBB, 0x44, 0xEE, 0x0F, 0x8E, 0xF2, 0x9E, 0x80, 0x8C, 0xBF, 0x2C, 0xBF, 0xB4, 0x59, 0x46, 0x55, 0x72, 0xFD, 0xFB, 0xA3, 0xC4, 0x34, 0x7F, 0x04, 0x37, 0xA7, 0x28, 0xD3, 0xA4, 0xDA, 0x73, 0x35, 0x40, 0x13, 0x1C, 0x94, 0xA8, 0xBF, 0x9E, 0xB0, 0x7C, 0x2D, 0xFB, 0x49, 0x9E, 0x6B, 0x00, 0xF8, 0xC1, 0xEC, 0x41, 0x8F, 0xAD, 0x5A, 0x81, 0x2B, 0x91, 0xF7, 0x4C, 0xCC, 0x98, 0xDD, 0x44, 0xEF, 0x2F, 0xB5, 0xE0, 0x35, 0xBF, 0x96, 0x99, 0x42, 0xB8, 0xB1, 0x4E, 0xDE, 0xB8, 0x0B, 0x66, 0x89, 0x84, 0x44, 0xBC, 0x7A, 0x10, 0x19, 0x69, 0xD2, 0x45, 0x46, 0x44, 0xA3, 0x49, 0x6F, 0x6E, 0xEC, 0xD9, 0x8B, 0xD7, 0xF8, 0x21, 0x50, 0x9B, 0x06, 0xF4, 0x6C, 0xDC, 0xC7, 0xC8, 0xFE, 0x88, 0x42, 0xEB, 0x9B, 0xC0, 0xF8, 0x00, 0x09, 0x44, 0xAE, 0xC0, 0x96, 0x84, 0xAF, 0x98, 0xD7, 0x5E, 0x02, 0xA3, 0x14, 0xC4, 0x63, 0x93, 0xFE, 0xEB, 0x88, 0x9C, 0x05, 0xB0, 0xE1, 0xB2, 0x2C, 0x53, 0xFC, 0xFE, 0xB2, 0xD7, 0x25, 0xB0, 0x64, 0x61, 0xB3, 0xF8, 0x32, 0x91, 0x5F, 0xCB, 0x44, 0xB1, 0x9F, 0x18, 0xCC, 0xBC, 0xB9, 0x62, 0x79, 0xA2, 0x86, 0x00, 0xD0, 0xBB, 0x74, 0xD1, 0x85, 0xF9, 0x17, 0x16, 0xA9, 0xCD, 0x1B, 0x32, 0xFD, 0x68, 0x80, 0x88, 0x31, 0x7D, 0x3D, 0x53, 0x56, 0x77, 0x5F, 0x95, 0xE1, 0x6C, 0x04, 0x90, 0x13, 0x20, 0x1F, 0xA3, 0x9B, 0x49, 0x89, 0x9E, 0x02, 0x05, 0xDA, 0xCD, 0x00, 0x39, 0xC9, 0xEF, 0xDF, 0x1D, 0xE6, 0x95, 0x1B, 0x94, 0x97, 0x20, 0xE8, 0x8F, 0xAF, 0x5E, 0x41, 0x2F, 0x8C, 0xDD, 0x98, 0x85, 0xFF, 0x52, 0xB6, 0x94, 0xBF, 0x61, 0xC5, 0xE9, 0xD9, 0x55, 0x99, 0x77, 0xAB, 0x7D, 0xAD, 0x6D, 0x96, 0xC5, 0x60, 0xD9, 0x42, 0x27, 0x90, 0xEC, 0xA9, 0x30, 0x53, 0x2D, 0xED, 0x12, 0xA0, 0xD0, 0x60, 0x3B, 0x8A, 0x39, 0xD9, 0x7A, 0x4C, 0xB1, 0x49, 0x9F, 0x81, 0xDB, 0x6C, 0x3A, 0x73, 0x3A, 0x11, 0xF3, 0x09, 0x13, 0x92, 0x09, 0x3E, 0x52, 0xC5, 0x51, 0xEB, 0x71, 0x6A, 0xB2, 0x05, 0xC2, 0xC0, 0x57, 0xF9, 0xEF, 0xD5, 0xBC, 0x35, 0xBD, 0xA8, 0x6C, 0xC8, 0xCA, 0xAE, 0xAC, 0x1B, 0x75, 0x85, 0xCD, 0x65, 0x5F, 0x9F, 0xB6, 0x8C, 0xAE, 0x57, 0x62, 0x07, 0x30, 0xF8, 0x15, 0x4E, 0xCB, 0x34, 0x67, 0xAF, 0x2A, 0xE2, 0x75, 0x9D, 0xFD, 0xC8, 0x92, 0xFA, 0x7A, 0xB1, 0x8D, 0xE4, 0x78, 0x44, 0x7A, 0x25, 0x9D, 0x07, 0x26, 0x9C, 0x84, 0xB9, 0x6D, 0x4A, 0x31, 0xD1, 0x72, 0xE9, 0x2A, 0xF9, 0x2E, 0xF9, 0x27, 0xD3, 0x96, 0x8B, 0x9D, 0x6D, 0xAE, 0x16, 0xB8, 0x84, 0x82, 0x07, 0xBD, 0x1C, 0x6B, 0x1C, 0x75, 0xD5, 0xD8, 0x63, 0x52, 0x1A, 0x2C, 0x61, 0xE5, 0x35, 0x2B, 0xE4, 0x3A, 0x13, 0x20, 0xA0, 0xEF, 0xBB, 0x64, 0x33, 0x4C, 0xF3, 0xA4, 0x5B, 0xD8, 0xC8, 0x04, 0x73, 0xD3, 0xC2, 0x1B, 0x95, 0x10, 0x79, 0x7D, 0xBC, 0x9A, 0x73, 0xB0, 0x71, 0x2A, 0x96, 0xA5, 0xAE, 0x66, 0xDC, 0x60, 0x9C, 0x06, 0x33, 0xEA, 0x90, 0x6B, 0xEE, 0x5A, 0xBE, 0x0E, 0x0E, 0x82, 0x83, 0x2E, 0x03, 0xBA, 0xD1, 0x7D, 0xDB, 0xCC, 0x26, 0x8C, 0xCF, 0x88, 0xD2, 0x35, 0x4C, 0x91, 0x61, 0x6F, 0xCD, 0x2E, 0xB4, 0x11, 0x76, 0xFA, 0x05, 0x40, 0x46, 0xD5, 0xA5, 0x8E, 0x95, 0xF6, 0x6D, 0xC6, 0x86, 0x98, 0xB7, 0x70, 0x54, 0xA6, 0x00, 0x59, 0xBA, 0x34, 0xE1, 0x0B, 0xB0, 0x3E, 0x41, 0x16, 0x1D, 0x19, 0xF1, 0x21, 0x00, 0xBF, 0x27, 0x3E, 0xA8, 0x61, 0x1A, 0xA0, 0x15, 0x8C, 0x9E, 0x36, 0x10, 0xD5, 0xBF, 0x58, 0x50, 0x47, 0x37, 0xA2, 0xB5, 0x17, 0xE3, 0xEB, 0x06, 0xA3, 0xCD, 0x26, 0xB7, 0x2C, 0x6B, 0x55, 0x38, 0xE4, 0xC7, 0x51, 0x33, 0x5E, 0x5E, 0x5A, 0xE1, 0x3B, 0xAE, 0x49, 0xED, 0x63, 0x87, 0xAB, 0x52, 0xDD, 0xDC, 0x73, 0x75, 0x46, 0xE3, 0xA2, 0x85, 0xDA, 0x37, 0xA3, 0x06, 0x4C, 0xC3, 0xC8, 0x4D, 0xB9, 0xEC, 0x3A, 0xC6, 0x83, 0xA8, 0xF2, 0x78, 0x15, 0xB8, 0xE1, 0x3D, 0xDA, 0xB1, 0x39, 0x0C, 0xF5, 0xAC, 0x7A, 0xDE, 0x58, 0x52, 0x2A, 0x1F, 0xD3, 0x4E, 0x3F, 0xE4, 0x4E, 0xF4, 0x56, 0xD9, 0x67, 0xC0, 0x72, 0xDC, 0x2F, 0x69, 0x30, 0xB8, 0x7A, 0x91, 0xAA, 0x58, 0xE4, 0x9E, 0xFD, 0x3B, 0xA6, 0xDB, 0x14, 0x4F, 0x2B, 0x40, 0x8F, 0xC0, 0xE5, 0x0C, 0x5E, 0x6B, 0x54, 0x41, 0x57, 0x18, 0x1F, 0x7C, 0xD9, 0x4F, 0x18, 0xC8, 0x69, 0xFF, 0xB0, 0x76, 0x4D, 0xCB, 0x8B, 0x50, 0x55, 0x28, 0xA3, 0xAC, 0x71, 0x55, 0xB9, 0xB1, 0x06, 0x87, 0x81, 0xA8, 0xF6, 0x4F, 0xBC, 0xE4, 0x64, 0xB0, 0xA0, 0x55, 0x8A, 0x5A, 0x91, 0x97, 0x76, 0x98, 0xE7, 0xF6, 0x36, 0x43, 0x79, 0x05, 0x83, 0xF1, 0x35, 0xDC, 0x6E, 0xEF, 0x97, 0xCB, 0x60, 0xF6, 0x45, 0x28, 0x75, 0x34, 0x6F, 0xF5, 0xBD, 0xBC, 0x5D, 0x27, 0x65, 0x52, 0xE4, 0xE3, 0xC4, 0x1C, 0x27, 0x7F, 0x80, 0x92, 0xFA, 0x8A, 0x21, 0x1A, 0xF5, 0x48, 0xA2, 0x55, 0x6A, 0x26, 0x5B, 0x3A, 0x4F, 0xCF, 0xEC, 0x66, 0x1B, 0x62, 0xCD, 0x88, 0x89, 0xAF, 0xFA, 0x89, 0x58, 0xAD, 0xF8, 0x6E, 0x80, 0xCA, 0xC9, 0xD0, 0x16, 0x86, 0x3B, 0xAB, 0xB0, 0x46, 0xC7, 0x04, 0x63, 0x6C, 0x08, 0x19, 0xAB, 0x50, 0xA6, 0x4D, 0xF1, 0x02, 0x08, 0x9E, 0xA7, 0x9C, 0x15, 0xA4, 0x89, 0x03, 0xC1, 0xE4, 0x39, 0xA3, 0xD4, 0x2A, 0x44, 0xC3, 0x08, 0x7B, 0xCE, 0x9C, 0x11, 0x69, 0x6A, 0x1A, 0x73, 0xFA, 0xCE, 0xB4, 0x10, 0x8E, 0x22, 0xA3, 0x53, 0xBD, 0x5E, 0x9E, 0x9B, 0xCF, 0x80, 0xC5, 0x17, 0x43, 0x04, 0x9D, 0xFD, 0x46, 0xAB, 0x24, 0xB7, 0x68, 0x81, 0xD2, 0xD1, 0x85, 0x70, 0xA0, 0x6C, 0xB1, 0x5C, 0x84, 0xC9, 0x86, 0x12, 0x8A, 0x65, 0x7D, 0xCE, 0xB9, 0x4D, 0x0F, 0x63, 0x26, 0x60, 0x21, 0x9E, 0xA0, 0x01, 0xCB, 0xF8, 0xF9, 0x6F, 0x17, 0xFC, 0xC8, 0x51, 0xF8, 0x64, 0xDC, 0x39, 0x2B, 0xAA, 0x18, 0x95, 0x1B, 0x6E, 0x15, 0xBC, 0xF5, 0xAF, 0x7C, 0x19, 0x91, 0x49, 0x91, 0x2D, 0x79, 0xE7, 0x00, 0x0D, 0x06, 0x3F, 0xF7, 0x93, 0x4B, 0x25, 0x23, 0xDA, 0xCE, 0x67, 0x71, 0xC5, 0xAB, 0xF7, 0x2E, 0x93, 0xC9, 0x1C, 0x1D, 0xEB, 0x77, 0x6B, 0xFD, 0xF2, 0x71, 0xA3, 0x78, 0xC7, 0xB5, 0x2E, 0x81, 0x48, 0x2E, 0x5E, 0xE8, 0x8B, 0x8C, 0x17, 0xE4, 0x31, 0xBF, 0xD2, 0xA5, 0x1A, 0x87, 0xC9, 0x47, 0xF1, 0x50, 0xE6, 0x1E, 0x55, 0x40, 0x33, 0xBE, 0xA3, 0x99, 0x85, 0x6D, 0xF2, 0x96, 0x79, 0x1F, 0x2A, 0x30, 0x9B, 0x03, 0x7A, 0xCB, 0xCC, 0x0B, 0x59, 0xCB, 0x36, 0x44, 0x0F, 0x10, 0xAB, 0x08, 0xE9, 0x34, 0x2E, 0xC3, 0xE2, 0x74, 0xE9, 0x2B, 0xF2, 0xF5, 0x0F, 0x00, 0x59, 0xA1, 0xBD, 0x4C, 0x42, 0x27, 0xF9, 0x74, 0x00, 0x62, 0x37, 0x5A, 0xAB, 0x54, 0x54, 0xA6, 0xB5, 0xAE, 0xDA, 0x4C, 0x33, 0xE0, 0x05, 0x6F, 0xC1, 0xDE, 0xBA, 0xC5, 0x15, 0xA8, 0xA4, 0x25, 0x58, 0x06, 0xF0, 0x17, 0xAB, 0xCF, 0x3D, 0x5F, 0x24, 0x2B, 0xE3, 0xFD, 0xB1, 0x41, 0xB5, 0xF3, 0x11, 0x13, 0x55, 0xBE, 0xD6, 0x91, 0xDA, 0x93, 0x2A, 0x15, 0x0A, 0x50, 0xB9, 0x67, 0xC8, 0xCD, 0xBF, 0xAE, 0x68, 0xEC, 0x54, 0xF7, 0xBF, 0xF0, 0x9A, 0x5B, 0xB2, 0xCD, 0x4F, 0x1C, 0x52, 0xC9, 0xF2, 0xC8, 0x23, 0xB5, 0x6A, 0x2B, 0x80, 0xD1, 0xAA, 0x54, 0x2A, 0x15, 0x3A, 0x07, 0xA2, 0x1D, 0x02, 0x20, 0x3E, 0x82, 0x7A, 0x6C, 0xC5, 0x33, 0xCF, 0x87, 0xC0, 0x8A, 0x64, 0x8B, 0x05, 0xD4, 0xC9, 0xD7, 0xCF, 0xB9, 0xD3, 0x0F, 0x71, 0xD3, 0x03, 0xC1, 0x68, 0x8C, 0x5E, 0x31, 0x19, 0xB7, 0x21, 0x6C, 0xB7, 0x0D, 0xD1, 0x57, 0x9C, 0x31, 0xDF, 0xF0, 0xD2, 0xE8, 0x7B, 0xED, 0xEB, 0x8C, 0xA9, 0x70, 0xD5, 0xA7, 0x72, 0xC1, 0xBE, 0x27, 0x53, 0x6F, 0xF6, 0xBF, 0x7B, 0x94, 0xD3, 0x3F, 0x98, 0xD3, 0x4C, 0x3E, 0x47, 0x4F, 0x23, 0x6A, 0x0D, 0xC7, 0x57, 0xB5, 0x22, 0x5E, 0x8C, 0x97, 0xB2, 0x37, 0x27, 0x7E, 0x59, 0x38, 0x9B, 0x9E, 0x84, 0xC4, 0x54, 0x84, 0xD3, 0xC5, 0x5F, 0x97, 0x5F, 0x29, 0xDA, 0x62, 0x28, 0x82, 0x6D, 0x4B, 0x76, 0x99, 0x24, 0xA5, 0x3A, 0x0F, 0x06, 0xB3, 0x27, 0x78, 0x4E, 0xE7, 0x15, 0x12, 0xC6, 0x6F, 0xB4, 0xEA, 0xB5, 0x73, 0xB1, 0x49, 0xA8, 0xB6, 0xC7, 0xB2, 0x48, 0x18, 0xAE, 0xBC, 0x15, 0x1A, 0x1C, 0x0B, 0x9F, 0xBD, 0x15, 0xCA, 0x66, 0x24, 0x1F, 0x71, 0xF2, 0xEB, 0x86, 0xB6, 0x15, 0x21, 0x06, 0x04, 0x77, 0xF0, 0x8A, 0x58, 0xC3, 0x9C, 0x40, 0x7F, 0x6E, 0xF4, 0x36, 0xC2, 0x2F, 0x8A, 0x12, 0xBF, 0xF3, 0x2E, 0x13, 0x1D, 0x09, 0xC7, 0x90, 0x56, 0x30, 0xBC, 0xB2, 0x00, 0x3A, 0x6D, 0xE7, 0x1E, 0x08, 0x49, 0x64, 0x90, 0x96, 0x19, 0xE3, 0x91, 0x3E, 0x01, 0x47, 0xE3, 0x8B, 0x77, 0x88, 0xA9, 0x92, 0x73, 0x49, 0x9E, 0x04, 0x0B, 0xA5, 0xD2, 0x86, 0xA1, 0xAC, 0x3D, 0x68, 0xC1, 0x0F, 0xDB, 0xA7, 0x6B, 0xA9, 0x6B, 0x65, 0x76, 0xF0, 0x45, 0x13, 0x10, 0x0D, 0xE9, 0xCA, 0xD5, 0x72, 0xEA, 0xE2, 0x88, 0x57, 0x59, 0x21, 0x31, 0x37, 0xEF, 0x35, 0x25, 0xF5, 0x02, 0x52, 0x59, 0xAE, 0xAB, 0xAD, 0xBA, 0x31, 0xDB, 0x94, 0xD8, 0xDB, 0xE3, 0x2B, 0x66, 0x7A, 0xCB, 0xC8, 0x80, 0x41, 0x8A, 0x57, 0x5F, 0x18, 0x34, 0x75, 0x02, 0x22, 0x28, 0xD7, 0x61, 0xED, 0x30, 0x62, 0x7A, 0x22, 0x7A, 0xDD, 0x54, 0xCB, 0x1E, 0x56, 0xC9, 0xA3, 0xF4, 0x66, 0x45, 0x28, 0x28, 0x63, 0xDE, 0x2B, 0xB2, 0x3D, 0x3B, 0xD1, 0x5F, 0xF0, 0x13, 0x49, 0xAF, 0xDD, 0x2F, 0x68, 0xAB, 0xAA, 0xE2, 0x73, 0x60, 0xCC, 0x2F, 0x6B, 0x60, 0x62, 0xE5, 0x53, 0x89, 0x47, 0x75, 0x5E, 0xFB, 0xD5, 0x03, 0x24, 0xB1, 0x4A, 0x46, 0xD3, 0x7C, 0xCE, 0x09, 0xD1, 0xD7, 0x0F, 0x4A, 0x80, 0x27, 0x00, 0x43, 0x63, 0x99, 0x48, 0x97, 0x10, 0x7E, 0x78, 0x80, 0xF1, 0x44, 0xA7, 0x92, 0x3A, 0x7D, 0x62, 0xC2, 0x4D, 0xEF, 0x3F, 0xD6, 0x7A, 0x57, 0x3C, 0xE5, 0x02, 0x8B, 0x4B, 0x68, 0xA5, 0xDE, 0x3B, 0x8F, 0x16, 0x4E, 0x67, 0x64, 0x69, 0x09, 0x53, 0xF1, 0xF0, 0x84, 0xB6, 0xBB, 0xF2, 0x22, 0xFD, 0x10, 0x89, 0x2F, 0x66, 0x7D, 0xBA, 0x8C, 0xC2, 0x27, 0xAB, 0xAC, 0xAF, 0x21, 0xC6, 0x18, 0x19, 0x0C, 0x8E, 0xEA, 0x1B, 0xB1, 0xDC, 0x03, 0xB3, 0x25, 0xE2, 0x81, 0x3F, 0x56, 0xA8, 0x79, 0xC0, 0x61, 0x87, 0xFE, 0x95, 0xE2, 0x95, 0xA9, 0x7F, 0x0C, 0x78, 0x8A, 0xB7, 0x01, 0x92, 0x6C, 0xD7, 0x56, 0x98, 0x77, 0x0D, 0x4F, 0xC8, 0xE5, 0x9E, 0xE6, 0x07, 0x3C, 0xFC, 0x1E, 0x08, 0xAC, 0xA1, 0x2B, 0x38, 0x9B, 0x85, 0x50, 0x60, 0xDA, 0x2D, 0x72, 0x89, 0xF4, 0xBD, 0x92, 0x15, 0x81, 0x79, 0xB3, 0xBB, 0x88, 0x9D, 0xD2, 0x97, 0x38, 0xCD, 0x49, 0xD7, 0x26, 0xE8, 0xE1, 0xA4, 0xF1, 0xC8, 0x70, 0xE2, 0x19, 0xCE, 0x60, 0xAA, 0x67, 0xF2, 0xC3, 0xB9, 0x20, 0x81, 0xBE, 0x2D, 0x31, 0x79, 0x08, 0x7E, 0x0B, 0xF2, 0x99, 0x61, 0xAB, 0x6D, 0x53, 0x84, 0x27, 0x0C, 0x2F, 0x59, 0xE0, 0x39, 0x2B, 0x4B, 0x6F, 0x26, 0x51, 0xB5, 0xB0, 0x16, 0x94, 0xA1, 0x8C, 0xB6, 0xF5, 0xA0, 0x15, 0xD8, 0x8E, 0x78, 0x72, 0xBB, 0xE9, 0xE2, 0x5D, 0xB7, 0x49, 0x60, 0xDF, 0x75, 0x00, 0x0B, 0x3F, 0xBF, 0x3B, 0xE3, 0x6D, 0x4D, 0xF1, 0x0D, 0xD5, 0xF0, 0x30, 0x90, 0x1B, 0x0E, 0x38, 0x05, 0xC4, 0x8B, 0xAF, 0x46, 0x6F, 0x07, 0x19, 0x83, 0x39, 0x43, 0x3B, 0x7C, 0x4C, 0x9F, 0x0D, 0x21, 0x9E, 0xB9, 0xE0, 0xC9, 0x1F, 0x6D, 0x4E, 0x83, 0xA2, 0xE8, 0x39, 0xE6, 0x72, 0x63, 0x26, 0x43, 0xDB, 0x89, 0x94, 0x64, 0x99, 0x7A, 0x7B, 0x6B, 0x72, 0xC0, 0x40, 0xB0, 0xD3, 0x41, 0x48, 0x6F, 0x13, 0xFB, 0xE7, 0x80, 0x68, 0xFB, 0xA6, 0x8E, 0x5E, 0x7F, 0x4A, 0x71, 0xA0, 0x3E, 0xD5, 0x6B, 0x76, 0x5C, 0xFA, 0x4C, 0xC1, 0xBA, 0x6A, 0x4D, 0x09, 0xFC, 0xF2, 0x09, 0xCB, 0xFE, 0xF2, 0xBD, 0x6C, 0xA1, 0x1C, 0x77, 0xA4, 0xB1, 0xFC, 0x9A, 0x67, 0x94, 0x00, 0x28, 0xF3, 0x85, 0xE6, 0xD3, 0xAB, 0x2A, 0x35, 0xE4, 0xEC, 0xEC, 0xDE, 0xB8, 0xE6, 0x3D, 0x39, 0x8B, 0x40, 0xA6, 0x71, 0xF2, 0xF5, 0x1E, 0xB7, 0xAE, 0x1F, 0x98, 0xA5, 0xC0, 0xC5, 0x3E, 0xF8, 0x18, 0x02, 0xF4, 0x2E, 0xD9, 0xCA, 0xB1, 0xEC, 0x3C, 0x85, 0x7B, 0x01, 0xAE, 0x6E, 0x30, 0x99, 0x19, 0xFD, 0x35, 0x91, 0xAC, 0xC4, 0xF4, 0xA9, 0x88, 0xEA, 0x36, 0xAD, 0xBF, 0x94, 0xF7, 0x69, 0xB9, 0xB3, 0x44, 0xA2, 0x10, 0x69, 0xA0, 0xF2, 0xD8, 0x3B, 0x25, 0x28, 0xEB, 0xB6, 0x1B, 0x05, 0x2A, 0x39, 0x2D, 0xD7, 0xC5, 0x06, 0x09, 0xF4, 0xC6, 0x1C, 0x7D, 0x8D, 0x57, 0x9B, 0x3D, 0x91, 0x96, 0xCE, 0xAE, 0xF3, 0xD6, 0x47, 0x54, 0x9A, 0x44, 0xC7, 0x8E, 0x99, 0x90, 0x53, 0xC5, 0x14, 0x91, 0x7D, 0xDB, 0x69, 0x96, 0xBB, 0xDA, 0x6A, 0xD6, 0x76, 0xF3, 0xED, 0xE5, 0x24, 0xDA, 0x55, 0x63, 0x9A, 0x12, 0x93, 0xFA, 0x3E, 0x03, 0xDB, 0xA5, 0x04, 0x71, 0xC2, 0x11, 0x5C, 0x6E, 0x45, 0x31, 0xEB, 0x97, 0xC3, 0x8E, 0x82, 0xE7, 0xA3, 0x1C, 0x41, 0xF7, 0xB4, 0x25, 0x60, 0x1E, 0x53, 0x28, 0x90, 0x4F, 0x65, 0x42, 0x16, 0x48, 0x7C, 0x17, 0xE9, 0x97, 0xA8, 0x32, 0x7B, 0x70, 0x3E, 0x8D, 0x3F, 0x15, 0xF6, 0x6A, 0xB7, 0xEC, 0x97, 0x31, 0x33, 0xBA, 0x65, 0x7F, 0x19, 0xCC, 0xFD, 0x05, 0xC4, 0xC9, 0xF0, 0xB6, 0xAB, 0x37, 0xD5, 0xC3, 0x38, 0x98, 0xBD, 0xF7, 0x82, 0x03, 0x4B, 0x70, 0xF4, 0xA0, 0x5B, 0x50, 0xB2, 0x17, 0x53, 0x26, 0xDD, 0x54, 0x7F, 0xD9, 0x92, 0x37, 0xE4, 0x2B, 0x87, 0xAF, 0xD7, 0x4E, 0xDE, 0x10, 0x64, 0x7F, 0xBD, 0xA3, 0xF9, 0xAF, 0xDB, 0xED, 0xA2, 0xB0, 0xE4, 0xE3, 0x9C, 0x59, 0x92, 0x79, 0xF7, 0x8D, 0x56, 0xC4, 0x06, 0x9D, 0x61, 0x13, 0xA4, 0xEB, 0x3F, 0x02, 0xB5, 0xC9, 0xD8, 0x0E, 0x82, 0x17, 0x96, 0x7D, 0x28, 0x46, 0x62, 0xA8, 0xBD, 0xDA, 0x30, 0x86, 0xE2, 0xCC, 0x4A, 0x64, 0x2A, 0x1F, 0x73, 0x30, 0x09, 0x31, 0x96, 0xCA, 0x04, 0x73, 0x03, 0xB1, 0xDE, 0xB8, 0xC7, 0xA2, 0xC3, 0x8C, 0xF9, 0xB8, 0x9D, 0xDC, 0xD2, 0xCF, 0x3F, 0xDB, 0xC2, 0x3A, 0xC6, 0x74, 0x6F, 0x29, 0x6C, 0x90, 0x21, 0x2B, 0xB5, 0x6F, 0xA8, 0xD2, 0x83, 0x2A, 0x61, 0x6E, 0x00, 0x9E, 0x3D, 0xF7, 0xD1, 0xA6, 0xEE, 0x83, 0x5B, 0x16, 0x19, 0xC6, 0x31, 0x67, 0xC6, 0x6F, 0x9E, 0x07, 0x33, 0xAE, 0x64, 0x31, 0xDE, 0x73, 0x7C, 0xDE, 0x65, 0xE2, 0x44, 0x1F, 0x60, 0x46, 0x96, 0x2B, 0x5E, 0x3D, 0x35, 0xCC, 0xB7, 0x0D, 0xBE, 0x17, 0xE6, 0x94, 0xEB, 0x92, 0x8A, 0xD7, 0xEA, 0x67, 0xCE, 0xF4, 0x7E, 0xCA, 0xBD, 0xA2, 0x36, 0x45, 0x15, 0x5B, 0x9E, 0x05, 0x1D, 0x6C, 0xA1, 0x3E, 0x13, 0xA8, 0x85, 0xB1, 0xB5, 0x35, 0x85, 0x2A, 0xA9, 0x51, 0x9A, 0x28, 0x1F, 0xAC, 0x1B, 0x31, 0xA8, 0x8E, 0x22, 0x35, 0xD1, 0xF9, 0x08, 0xDA, 0xD9, 0x8D, 0x62, 0xD4, 0x26, 0x01, 0x6B, 0x8A, 0xB9, 0x07, 0x72, 0x64, 0xF8, 0x56, 0x2A, 0xB9, 0x37, 0x9D, 0x9A, 0xFE, 0x98, 0xEB, 0xAE, 0xA7, 0xB5, 0xBD, 0xB6, 0xBB, 0xB1, 0xED, 0xCE, 0xE2, 0x8B, 0x77, 0x91, 0x87, 0xBF, 0x8A, 0x21, 0x46, 0x23, 0xB4, 0xAC, 0x18, 0x30, 0x75, 0xCA, 0x6C, 0x19, 0x9F, 0x2D, 0x87, 0xE5, 0x76, 0x2B, 0x22, 0x1A, 0x70, 0x5A, 0x04, 0xC1, 0x35, 0x0B, 0x6A, 0xBE, 0xEB, 0xD6, 0xED, 0xDF, 0xCC, 0xC8, 0x27, 0x29, 0x70, 0x06, 0x54, 0xB1, 0xA2, 0x41, 0x05, 0xB9, 0x5F, 0x6A, 0x1D, 0x6A, 0xEB, 0xE9, 0xE6, 0x67, 0xBD, 0x99, 0x55, 0x08, 0x47, 0xF2, 0xBB, 0x4B, 0xD2, 0x6F, 0x03, 0xB2, 0x44, 0x55, 0xDC, 0xE8, 0xC5, 0xD8, 0x17, 0xF1, 0x8A, 0xE3, 0x0E, 0x0A, 0xCA, 0xEC, 0x8B, 0x82, 0x41, 0xD3, 0x43, 0xB4, 0x15, 0xF9, 0x78, 0xD5, 0x1E, 0xDC, 0xA1, 0x42, 0x42, 0x18, 0x1E, 0x53, 0x49, 0xFA, 0xC6, 0x7C, 0x85, 0x1A, 0x4E, 0x0F, 0x6D, 0x89, 0x96, 0x9F, 0x02, 0x2B, 0xD9, 0x6E, 0xD7, 0x6D, 0x4A, 0x86, 0x6D, 0xE3, 0xFD, 0xEE, 0xD7, 0xAF, 0x42, 0x19, 0xD4, 0x3D, 0x0B, 0x34, 0x68, 0x8D, 0x6C, 0xF8, 0x3C, 0x31, 0xEC, 0x89, 0xA9, 0x11, 0x1F, 0x4D, 0xC6, 0x62, 0x59, 0xE9, 0x95, 0x77, 0xCC, 0x21, 0x9E, 0x52, 0x04, 0x3E, 0xE8, 0x80, 0x7C, 0x23, 0x5F, 0x25, 0x31, 0x57, 0x36, 0x9F, 0xF0, 0x8B, 0xAF, 0x1D, 0xE1, 0x8A, 0xCD, 0x51, 0x6D, 0x70, 0x86, 0xE1, 0x55, 0x62, 0x6D, 0x21, 0xCC, 0xCE, 0xD0, 0x32, 0x67, 0x97, 0x32, 0x79, 0xBF, 0xBE, 0xAB, 0xFA, 0x1D, 0x5C, 0x60, 0xD1, 0xBF, 0xB6, 0x97, 0x75, 0xD2, 0x58, 0x3B, 0xE8, 0xC0, 0x40, 0xC9, 0x93, 0xAB, 0x91, 0x43, 0x13, 0xCB, 0x6D, 0x1D, 0x7B, 0x41, 0xFC, 0xC4, 0x68, 0x8E, 0x17, 0x5F, 0x12, 0x31, 0x0C, 0x2C, 0x87, 0x82, 0x0C, 0xE6, 0x2E, 0xCB, 0x40, 0x5E, 0x8C, 0xC0, 0x42, 0xFD, 0x78, 0x7F, 0xE0, 0x72, 0x61, 0xEE, 0x0A, 0xF7, 0x75, 0xB6, 0x3D, 0x52, 0xDB, 0xB6, 0x02, 0x59, 0x0D, 0x49, 0xF1, 0x2B, 0x23, 0x57, 0xCB, 0x63, 0x12, 0x6A, 0xDA, 0x6A, 0xDF, 0x23, 0x0D, 0x05, 0xD6, 0x0A, 0xE1, 0x6D, 0x98, 0x48, 0xE2, 0xAB, 0xAB, 0x0A, 0x8D, 0x0C, 0xC4, 0xAF, 0xEE, 0xFA, 0x0D, 0x05, 0x1B, 0xB0, 0x77, 0xFC, 0x57, 0xEE, 0x04, 0x0D, 0x61, 0x81, 0x5D, 0x87, 0xF4, 0xB4, 0xBC, 0x5E, 0xF0, 0x18, 0x49, 0x63, 0x6D, 0xE9, 0xAD, 0x98, 0x54, 0xDD, 0xFF, 0xD9, 0xDE, 0x77, 0xF5, 0x48, 0x8E, 0x24, 0x69, 0x3E, 0xCF, 0x01, 0xF7, 0x1F, 0x12, 0xFD, 0x30, 0xDB, 0x03, 0x0E, 0x9A, 0x2A, 0x18, 0x64, 0xEC, 0x08, 0x80, 0x0C, 0xAA, 0xA0, 0x0E, 0x06, 0xF5, 0xCB, 0x80, 0x5A, 0x6B, 0x15, 0xE4, 0x62, 0xFE, 0xFB, 0x31, 0xB2, 0xAA, 0xBA, 0xAB, 0xEB, 0xAA, 0xAB, 0xFB, 0xB6, 0x17, 0x8B, 0x05, 0x6E, 0x12, 0x08, 0x24, 0xE9, 0xE6, 0x66, 0x2E, 0xCD, 0xCD, 0x3E, 0xA7, 0x8B, 0xB9, 0xAE, 0x45, 0x55, 0xED, 0x16, 0x77, 0x28, 0x0D, 0x4D, 0xA9, 0x38, 0xC6, 0x1F, 0x62, 0x7D, 0x1A, 0x5F, 0x36, 0x71, 0x74, 0x30, 0x8E, 0xBB, 0xB3, 0xDD, 0x85, 0xC3, 0xB3, 0xDE, 0x80, 0x83, 0xAA, 0xB9, 0xD0, 0xF0, 0xC5, 0x08, 0xA0, 0x07, 0xD5, 0x5C, 0x0F, 0x56, 0x7F, 0xEA, 0x0D, 0x85, 0x54, 0xA9, 0xC3, 0xCD, 0x64, 0x8F, 0xDC, 0xED, 0xA6, 0xD8, 0x6E, 0x28, 0x9C, 0x53, 0x1A, 0x20, 0x9D, 0xD5, 0x61, 0xC3, 0x66, 0x7C, 0x24, 0x08, 0x0D, 0xF7, 0x94, 0x87, 0xC5, 0xAA, 0x91, 0xD6, 0xB6, 0xB9, 0x5C, 0xDC, 0x76, 0x53, 0x80, 0x19, 0x5C, 0x9F, 0x87, 0xE6, 0xB6, 0xFB, 0x9D, 0xBE, 0x67, 0xB7, 0x95, 0x5F, 0xAE, 0xE4, 0xD6, 0x21, 0x28, 0x88, 0x5F, 0x8E, 0x31, 0xF4, 0xDA, 0x66, 0x71, 0xE4, 0x66, 0x31, 0x47, 0xE7, 0x30, 0xA4, 0xD8, 0xFC, 0x02, 0xDE, 0x61, 0x56, 0xEC, 0x78, 0xB8, 0xA1, 0xD6, 0xB8, 0x11, 0xDD, 0x76, 0xBB, 0x92, 0x74, 0x15, 0x66, 0x4D, 0x65, 0x8E, 0xCD, 0xB9, 0xA8, 0x19, 0xF7, 0x50, 0x8C, 0x7D, 0x13, 0xBD, 0xE8, 0xFD, 0x88, 0x8E, 0x8A, 0xD4, 0x64, 0xD5, 0xAA, 0xD2, 0x03, 0xAA, 0x34, 0x04, 0x4C, 0x56, 0x6D, 0x67, 0xF7, 0xCB, 0xA1, 0x76, 0x5C, 0x73, 0x7B, 0x5A, 0x3C, 0x7F, 0x81, 0x6B, 0xD5, 0x32, 0xC5, 0x1C, 0x07, 0xD4, 0x63, 0x24, 0xAA, 0xA3, 0xDE, 0x60, 0x53, 0x3C, 0x81, 0x34, 0xFD, 0x6E, 0xDA, 0xD2, 0x7A, 0xE4, 0xB1, 0x7B, 0x00, 0x8D, 0xD1, 0x1B, 0x8D, 0x19, 0x0A, 0x97, 0xB4, 0xBF, 0xA6, 0xBC, 0x88, 0x15, 0x82, 0x7C, 0x38, 0x1B, 0x29, 0x7C, 0xE9, 0x34, 0x0D, 0x8B, 0x68, 0xA6, 0xAD, 0x7B, 0x00, 0xD2, 0x63, 0xBF, 0xF2, 0x46, 0x01, 0x4E, 0xE8, 0xBA, 0xA6, 0x43, 0x99, 0x7C, 0x82, 0x10, 0x0F, 0x45, 0x35, 0x22, 0x94, 0x88, 0x27, 0x8B, 0xE0, 0x3C, 0xAB, 0xB1, 0x0B, 0xD1, 0x56, 0xDE, 0x91, 0xD1, 0x01, 0xD7, 0x82, 0xB9, 0x64, 0x97, 0x44, 0x2B, 0x02, 0x67, 0x9F, 0x86, 0x67, 0xAB, 0xDF, 0xD5, 0xDB, 0xA6, 0x16, 0x29, 0xD6, 0xD6, 0x95, 0xBB, 0x9C, 0xA7, 0x58, 0x2C, 0x47, 0x6D, 0x22, 0x87, 0x45, 0x08, 0xDA, 0x1B, 0xC8, 0xF0, 0x57, 0x96, 0x3A, 0x51, 0xF9, 0xED, 0x7E, 0xC1, 0x60, 0xBE, 0x69, 0xA8, 0x88, 0x6B, 0x10, 0x80, 0xA1, 0xEA, 0x95, 0x45, 0x62, 0x52, 0x24, 0xD6, 0x7B, 0x93, 0x1B, 0x26, 0x48, 0x10, 0x20, 0xEC, 0xAD, 0x54, 0xE9, 0xDE, 0x01, 0x66, 0x65, 0xC6, 0xA6, 0x8E, 0x77, 0xAB, 0x3A, 0x8B, 0x77, 0x9F, 0x14, 0xB2, 0x6E, 0x89, 0xA5, 0x73, 0x28, 0xDF, 0xE9, 0x25, 0x6F, 0xD7, 0xEB, 0x59, 0xD0, 0x68, 0x22, 0xBE, 0x12, 0x00, 0xBA, 0x92, 0x32, 0xC9, 0x1D, 0xC3, 0x1D, 0xF0, 0x14, 0x59, 0x14, 0xE8, 0x4E, 0x32, 0x75, 0x17, 0x12, 0x0B, 0x1A, 0xC4, 0xE7, 0x8A, 0xD2, 0x2A, 0xBB, 0xDB, 0x63, 0x42, 0x3F, 0x07, 0x03, 0x51, 0x87, 0x65, 0x44, 0x0F, 0xEF, 0x2D, 0x5B, 0x40, 0x01, 0x40, 0x4F, 0x13, 0xC1, 0x39, 0x0A, 0x7B, 0x0F, 0x36, 0xF9, 0xB4, 0x17, 0xB7, 0xB2, 0xD5, 0xB9, 0x36, 0xD5, 0x03, 0x0D, 0x9F, 0xD2, 0x64, 0x1C, 0x8F, 0x81, 0x13, 0x85, 0x32, 0x6F, 0x9E, 0xE3, 0xA3, 0x7A, 0x2C, 0x70, 0xB8, 0x3E, 0x23, 0x4E, 0x97, 0x4A, 0x5B, 0x1F, 0xF4, 0xB9, 0x7B, 0xC8, 0xB6, 0xCF, 0xB2, 0x88, 0xED, 0x62, 0x76, 0x7A, 0x93, 0xD7, 0x0B, 0xA0, 0xE8, 0x0E, 0xDA, 0xD7, 0x73, 0xB6, 0x31, 0x32, 0xF1, 0xCC, 0x0F, 0xDC, 0x83, 0x9F, 0x9F, 0x37, 0xA2, 0x2E, 0x31, 0xF8, 0xE2, 0xE9, 0x90, 0xD4, 0xA0, 0xDD, 0x5A, 0x02, 0xF3, 0x29, 0xF0, 0xE5, 0x66, 0xA1, 0x6B, 0xD6, 0x82, 0xB1, 0x25, 0x3D, 0x13, 0x1D, 0x1E, 0x63, 0x11, 0x52, 0xA9, 0x0F, 0xC1, 0x9E, 0xC5, 0xEE, 0xE6, 0x53, 0x6D, 0x3A, 0x11, 0x51, 0x10, 0xA3, 0xF9, 0xCA, 0xA6, 0x9D, 0x73, 0x97, 0x92, 0x85, 0x3D, 0x69, 0x4E, 0x76, 0xC0, 0xD4, 0x92, 0x4C, 0xB2, 0x56, 0xCC, 0x30, 0xBE, 0xC5, 0xC9, 0x7B, 0xF6, 0x54, 0x91, 0xE1, 0xDA, 0xF3, 0x5C, 0xE3, 0x8D, 0x68, 0x80, 0xE1, 0xE4, 0x50, 0x56, 0x05, 0x62, 0x8B, 0xD7, 0x7E, 0x9E, 0xFD, 0xDB, 0x8E, 0x80, 0x8C, 0xF1, 0xAA, 0x12, 0xA3, 0x25, 0xC3, 0x4C, 0x4F, 0xA9, 0xED, 0x6A, 0x74, 0xD3, 0x59, 0x89, 0xF0, 0x10, 0x3D, 0x20, 0x8A, 0xED, 0x68, 0x01, 0x06, 0xF1, 0x37, 0xA8, 0x22, 0xDB, 0x8B, 0xEC, 0x43, 0x9C, 0xA1, 0xA8, 0xC0, 0xD1, 0xDF, 0xC9, 0x51, 0x5E, 0xD7, 0xD5, 0x38, 0x5D, 0xA1, 0x6B, 0x8C, 0xA5, 0xEB, 0x19, 0xB8, 0x30, 0x3C, 0xD8, 0xB3, 0xCB, 0xDA, 0xEA, 0xCA, 0x59, 0xB5, 0x78, 0xFC, 0x52, 0xD0, 0x26, 0x7F, 0x83, 0x95, 0x84, 0xE2, 0xB3, 0xDA, 0x54, 0xAA, 0xD9, 0x32, 0x65, 0x9D, 0x26, 0xE8, 0x3B, 0xCC, 0x77, 0xCD, 0x40, 0x91, 0x04, 0x0D, 0x92, 0xE8, 0xDE, 0xCF, 0xD3, 0x05, 0x1E, 0xF2, 0xD6, 0xFD, 0x0D, 0xDB, 0xC3, 0xDE, 0x27, 0xB1, 0x1F, 0xFE, 0x34, 0xFE, 0x0F, 0x99, 0xC4, 0x7E, 0xED, 0xFE, 0x1A, 0x27, 0xBF, 0xFE, 0x72, 0xE5, 0xD1, 0xF4, 0x29, 0xFC, 0xBF, 0x74, 0x4A, 0x5B, 0x3A, 0x78, 0xE2, 0xE8, 0x8B, 0xA4, 0xAA, 0xF7, 0xC0, 0xDF, 0x35, 0x49, 0x2C, 0xF9, 0x53, 0x3E, 0xCD, 0xD1, 0x97, 0x93, 0xDA, 0x95, 0x3F, 0xFD, 0x3E, 0xB1, 0x6D, 0x93, 0x7E, 0x55, 0xEE, 0xEF, 0x5C, 0x2D, 0x75, 0xB4, 0x7F, 0x5C, 0x55, 0x47, 0x3B, 0x7D, 0x39, 0xA5, 0x3D, 0xBE, 0x3A, 0xC6, 0x7F, 0x52, 0xF2, 0xA7, 0xE9, 0xED, 0xDF, 0xD6, 0xEE, 0xDA, 0x10, 0x87, 0xF9, 0x57, 0xD6, 0x83, 0x65, 0x51, 0xFB, 0x53, 0x93, 0x7F, 0x58, 0xA9, 0x84, 0xBD, 0x0E, 0xBB, 0xFB, 0xD7, 0xCC, 0xFA, 0xBF, 0x96, 0x61, 0xFD, 0xE6, 0x99, 0xF5, 0x90, 0xFB, 0x6C, 0x19, 0x16, 0x1E, 0xB0, 0x9A, 0xC3, 0x85, 0x14, 0x78, 0xB9, 0xF4, 0x98, 0x32, 0xBA, 0x32, 0x86, 0x38, 0x7C, 0x6A, 0x3C, 0xC9, 0xEE, 0x9E, 0x5D, 0xD5, 0xF1, 0x3E, 0xF0, 0x3A, 0x89, 0x50, 0x55, 0xD9, 0xF6, 0x6C, 0x99, 0x3C, 0x38, 0x79, 0xED, 0x2C, 0x9B, 0x55, 0x14, 0xB2, 0xCD, 0xC5, 0xF6, 0xF6, 0x58, 0xCA, 0xA2, 0xC6, 0x5D, 0x21, 0x7A, 0x20, 0x23, 0x72, 0x16, 0x0F, 0x84, 0x37, 0x9E, 0x4B, 0xA9, 0x43, 0x6A, 0xD0, 0xBD, 0x5F, 0x71, 0xEA, 0x81, 0x2C, 0x16, 0x25, 0x5A, 0x54, 0xFC, 0x70, 0xA9, 0xFA, 0xB0, 0xE7, 0xF1, 0x03, 0xDB, 0x99, 0x50, 0x97, 0x82, 0x38, 0x6A, 0x1C, 0x6D, 0x19, 0x8B, 0xD3, 0x03, 0xA7, 0xF6, 0xF1, 0x30, 0x8E, 0xC4, 0x30, 0x1B, 0x7B, 0xBF, 0xED, 0x60, 0x0D, 0x10, 0x18, 0x7A, 0x58, 0xF0, 0xE4, 0x8C, 0x36, 0x1A, 0xC1, 0x47, 0xB4, 0x0E, 0x45, 0xFC, 0x4F, 0xBF, 0xA4, 0x04, 0x75, 0x75, 0x40, 0x35, 0xDD, 0x3A, 0x71, 0x4B, 0x8A, 0x94, 0xBC, 0x6F, 0x0C, 0x34, 0x71, 0x59, 0xE9, 0xC3, 0xCD, 0x66, 0x53, 0x19, 0xA4, 0x5C, 0x97, 0x85, 0xC2, 0x24, 0x78, 0x86, 0x57, 0x9F, 0xA4, 0x63, 0x0A, 0x3D, 0xD1, 0x8A, 0x16, 0x3A, 0x52, 0xC7, 0x93, 0xD0, 0x39, 0x84, 0x3C, 0x81, 0x25, 0x2B, 0xBA, 0x4D, 0xCE, 0x14, 0x89, 0xE9, 0x1E, 0x86, 0x0A, 0x23, 0xB8, 0x8B, 0xDE, 0x8D, 0x08, 0x04, 0xE0, 0x69, 0xE5, 0x7A, 0x4B, 0x26, 0x62, 0x76, 0xD9, 0xBA, 0xE6, 0x61, 0x91, 0xF3, 0x91, 0x00, 0x3B, 0xA5, 0x1B, 0x22, 0x30, 0x44, 0x05, 0xEF, 0x0F, 0x8A, 0x62, 0x6A, 0xE0, 0x30, 0xA3, 0x9A, 0xE6, 0xDE, 0x72, 0x83, 0xB1, 0x8D, 0x1C, 0x06, 0xCE, 0x20, 0x01, 0x51, 0x48, 0x47, 0x53, 0xDC, 0xC9, 0xF3, 0xA8, 0x9A, 0x44, 0x47, 0x2E, 0x2B, 0xCC, 0xC2, 0x5F, 0xBA, 0x10, 0xE4, 0x7C, 0x43, 0x2F, 0x4A, 0xD2, 0xC7, 0x01, 0x1C, 0x38, 0x73, 0xD7, 0xBB, 0xD0, 0xA1, 0xE6, 0xB5, 0x40, 0xFD, 0xC0, 0xBF, 0x3F, 0xA1, 0xD0, 0x6B, 0x67, 0x06, 0xB9, 0x3E, 0xD2, 0xC3, 0xBE, 0xAE, 0xBB, 0x7D, 0x61, 0x6E, 0x89, 0x4E, 0x31, 0x14, 0xAF, 0xCA, 0x86, 0x30, 0x54, 0x9E, 0x7F, 0x60, 0x7B, 0xFC, 0x9C, 0xA8, 0x77, 0x49, 0x72, 0x5F, 0x13, 0x70, 0x3E, 0x99, 0xE4, 0x25, 0x04, 0xA9, 0x34, 0x52, 0x20, 0x6D, 0x30, 0x08, 0xD4, 0x29, 0x64, 0x9F, 0xB9, 0x95, 0x95, 0x24, 0xAE, 0xA3, 0x10, 0x9B, 0x39, 0xC6, 0xB3, 0x77, 0x48, 0xBF, 0x57, 0xEE, 0xD2, 0x40, 0xFB, 0xCA, 0x81, 0x80, 0x71, 0x9E, 0x7F, 0x12, 0xBD, 0x5F, 0x5E, 0xEE, 0x8C, 0x3A, 0xCB, 0x60, 0x0E, 0x4F, 0xA9, 0x9F, 0x78, 0x10, 0x5D, 0x20, 0x40, 0xEE, 0xF7, 0xB6, 0xBE, 0x08, 0x09, 0x18, 0xD7, 0x2B, 0x50, 0xD5, 0x62, 0x66, 0xAA, 0x5E, 0x1C, 0x3E, 0x4D, 0x96, 0x5A, 0xDD, 0xD0, 0xBE, 0x96, 0x8C, 0x63, 0x6F, 0x8C, 0x41, 0xB6, 0xA0, 0x83, 0x2F, 0xF5, 0x73, 0xEC, 0x7B, 0xB2, 0x82, 0xC6, 0x46, 0xF7, 0xC8, 0x40, 0xD9, 0x96, 0x27, 0xCE, 0x8B, 0xD1, 0xEA, 0x6F, 0xEB, 0x64, 0x9F, 0xD8, 0xD9, 0x2D, 0x60, 0xD8, 0x42, 0xEC, 0xCA, 0x21, 0xB4, 0x9A, 0x30, 0x13, 0xC7, 0x6C, 0xE5, 0x81, 0xDD, 0x9A, 0x1B, 0x00, 0x2C, 0xD4, 0x45, 0x29, 0x22, 0x93, 0x10, 0xB0, 0x42, 0x4A, 0x29, 0x11, 0x87, 0x16, 0xF5, 0x46, 0x32, 0xF9, 0x0D, 0x61, 0x42, 0x25, 0x09, 0x1D, 0x92, 0xA6, 0x33, 0x22, 0x67, 0xCB, 0x33, 0x9A, 0x03, 0x33, 0xDB, 0x6B, 0x90, 0x9D, 0x13, 0x32, 0xAE, 0x0A, 0xB7, 0x73, 0xEB, 0xAF, 0x33, 0x88, 0xCA, 0x0E, 0x88, 0x44, 0xCC, 0x0D, 0xD0, 0x70, 0x7C, 0xF4, 0x9C, 0xEB, 0xD4, 0x94, 0x1B, 0xD0, 0x0A, 0x6E, 0xCA, 0xB8, 0x07, 0xB0, 0x24, 0xB3, 0x42, 0xE9, 0x96, 0x25, 0x0F, 0x4B, 0xFA, 0x21, 0x08, 0x64, 0x99, 0xDF, 0x4D, 0xFD, 0xC1, 0xA4, 0x6B, 0xC6, 0x6F, 0x31, 0x30, 0x45, 0xCA, 0x3A, 0x40, 0xA4, 0xFC, 0xC8, 0x51, 0x65, 0xE8, 0x4F, 0xD1, 0xEE, 0xED, 0x7B, 0x85, 0x63, 0x85, 0x61, 0x8C, 0x19, 0xEA, 0x32, 0xD0, 0xEB, 0x07, 0x9D, 0xCA, 0xF1, 0x39, 0xC6, 0x88, 0x6B, 0x48, 0x31, 0x56, 0x8B, 0xE3, 0xA0, 0x15, 0x44, 0x6E, 0x6F, 0x17, 0x87, 0xC4, 0xCC, 0xD9, 0xE2, 0xE9, 0x0A, 0x2A, 0x99, 0xAD, 0x31, 0x02, 0xAD, 0x32, 0x24, 0x6E, 0xBD, 0x9C, 0x9D, 0x08, 0x56, 0x1C, 0x2B, 0x9C, 0x2D, 0x11, 0x76, 0x49, 0x00, 0xD3, 0x13, 0x15, 0x8A, 0x85, 0xD9, 0x9B, 0x13, 0x64, 0x30, 0xF2, 0xC7, 0xCE, 0x1E, 0x20, 0x24, 0x2A, 0x55, 0xA3, 0xC1, 0x10, 0x4D, 0xF0, 0x3B, 0x5F, 0x36, 0xA0, 0xFB, 0x05, 0x84, 0x51, 0x49, 0x23, 0xCE, 0xF7, 0xCB, 0x42, 0x84, 0x31, 0xC8, 0x5F, 0x03, 0x2B, 0x18, 0x63, 0xBB, 0x16, 0x0B, 0x01, 0xEA, 0xF6, 0x2E, 0x50, 0x90, 0xAD, 0xB4, 0x15, 0xBE, 0x40, 0xE9, 0xA7, 0x83, 0x3B, 0x6E, 0x70, 0xAB, 0x68, 0xFB, 0x76, 0x53, 0xCE, 0xA7, 0x11, 0x4B, 0x80, 0x93, 0x0C, 0x80, 0x3E, 0x68, 0x98, 0x1E, 0x27, 0xB4, 0x7C, 0x0A, 0x5E, 0xDC, 0xF0, 0x61, 0x56, 0x82, 0x26, 0xB1, 0xF3, 0x91, 0x0D, 0x78, 0xB2, 0xF4, 0x68, 0xB8, 0x47, 0xE7, 0x14, 0xBF, 0xE4, 0x80, 0x7D, 0x13, 0xAF, 0x55, 0xB8, 0xB9, 0x90, 0xAB, 0xD6, 0x56, 0xE3, 0xD5, 0x03, 0xCE, 0xCA, 0x0D, 0xEE, 0x12, 0x77, 0xB7, 0xE8, 0xD2, 0x2B, 0x34, 0x39, 0xED, 0xFD, 0xDE, 0x5D, 0x1F, 0xE5, 0x28, 0x36, 0xDD, 0xD6, 0xE6, 0x18, 0x63, 0x0E, 0x07, 0x46, 0x96, 0xA9, 0x85, 0xC5, 0x16, 0xAF, 0xA3, 0x03, 0x1B, 0x99, 0x8E, 0xBC, 0x10, 0x47, 0xE7, 0xB0, 0x83, 0x4D, 0x07, 0xB7, 0x20, 0x84, 0x1C, 0x17, 0x68, 0xB2, 0x10, 0x57, 0xE9, 0x39, 0x50, 0x77, 0x40, 0x3B, 0xF5, 0xC9, 0xED, 0x66, 0x6F, 0xE0, 0x12, 0xBB, 0xAC, 0x6D, 0x9C, 0x5E, 0xC7, 0x73, 0x4D, 0x44, 0x2F, 0x76, 0x62, 0x4F, 0x24, 0x74, 0x31, 0x47, 0x12, 0xA2, 0xB1, 0xC4, 0xE3, 0xB1, 0xCD, 0x34, 0x34, 0x84, 0xCD, 0xCA, 0x35, 0x06, 0x0A, 0x73, 0x48, 0xC8, 0x81, 0xE1, 0x42, 0x2D, 0xC9, 0x09, 0x47, 0x4D, 0x51, 0xCE, 0xF1, 0x94, 0xBB, 0x7B, 0x41, 0xB3, 0x84, 0xC8, 0x3E, 0x4B, 0xC0, 0x2D, 0x4E, 0xA5, 0x95, 0x67, 0x61, 0x89, 0xC0, 0xF8, 0xC1, 0x06, 0x67, 0x5A, 0x88, 0x49, 0x02, 0x16, 0x6B, 0xE1, 0x4C, 0x4D, 0x69, 0xE4, 0xEB, 0xA9, 0x4C, 0x75, 0x82, 0x61, 0xA6, 0xB1, 0xAE, 0xEE, 0x57, 0x6F, 0x67, 0x36, 0x08, 0x09, 0xEE, 0x48, 0x7F, 0xE8, 0x8F, 0x04, 0x9C, 0xA6, 0xC2, 0xEF, 0x02, 0x10, 0x23, 0xCE, 0xBB, 0x1A, 0xB4, 0xE0, 0xD9, 0x71, 0x79, 0xBB, 0x64, 0x52, 0x88, 0x9B, 0xB4, 0x89, 0xAD, 0xEF, 0x3B, 0xE7, 0x8D, 0xF4, 0x18, 0x8E, 0x41, 0x4A, 0x48, 0x14, 0x2B, 0xB9, 0x91, 0x5A, 0x2D, 0x88, 0x22, 0x19, 0xBE, 0xBD, 0xF5, 0xB9, 0x77, 0x9D, 0xFD, 0x18, 0xE7, 0xB0, 0x78, 0x20, 0x7D, 0x00, 0x6D, 0x1E, 0x89, 0x3D, 0x84, 0xC1, 0x72, 0x41, 0xE6, 0x0D, 0x3F, 0x13, 0x03, 0xD6, 0x55, 0x93, 0x8A, 0x1C, 0x63, 0xE6, 0x2C, 0x02, 0x7E, 0x12, 0x6A, 0x2A, 0x7E, 0x6D, 0x9E, 0x2E, 0xEA, 0x9C, 0x37, 0x0B, 0xDF, 0xA6, 0x47, 0x7B, 0xA8, 0x53, 0xAD, 0x1F, 0xD5, 0xA9, 0x52, 0xCF, 0xCE, 0xAE, 0xA6, 0x28, 0xB8, 0xC3, 0xC2, 0x16, 0xD6, 0xC4, 0xE5, 0x36, 0x27, 0x21, 0x40, 0x2B, 0x30, 0x6E, 0x21, 0xFD, 0xE5, 0x80, 0xEE, 0xAF, 0xAA, 0x1A, 0xCF, 0x04, 0xA5, 0xB3, 0xC8, 0x3D, 0x67, 0xAC, 0x05, 0x07, 0xE8, 0x2C, 0x51, 0x1A, 0x28, 0xC6, 0x10, 0x68, 0x57, 0x2B, 0x57, 0xCD, 0x2B, 0x82, 0xBD, 0x86, 0x80, 0x76, 0x37, 0x1E, 0x0D, 0x70, 0xA9, 0x10, 0x32, 0x95, 0x55, 0xBA, 0x27, 0xAF, 0xB9, 0x98, 0xEB, 0x1A, 0xAF, 0x01, 0x81, 0xA2, 0xC0, 0xA7, 0x8A, 0x25, 0x5B, 0xC5, 0x07, 0x66, 0x9A, 0xBE, 0xE0, 0xC5, 0xAA, 0xE1, 0x0E, 0x85, 0xD9, 0x60, 0x7C, 0x7E, 0xC8, 0x24, 0x4E, 0x04, 0xA2, 0x00, 0x84, 0xA5, 0xDB, 0xB0, 0x72, 0x86, 0xC3, 0xDD, 0xC0, 0xE9, 0xC2, 0x6D, 0x15, 0xAE, 0xF6, 0x13, 0x8C, 0xD2, 0x89, 0x47, 0x77, 0x88, 0x20, 0xD2, 0x06, 0xBE, 0x19, 0xB7, 0xC7, 0x33, 0xAD, 0x75, 0x73, 0xD3, 0x19, 0xA3, 0x63, 0xEF, 0x02, 0xDB, 0xB8, 0xF8, 0x1D, 0xD7, 0x61, 0xA5, 0x35, 0xCC, 0x7B, 0xE7, 0x0C, 0x94, 0x48, 0x02, 0x1A, 0x7D, 0xAA, 0xFD, 0x62, 0xCB, 0xDC, 0xD9, 0xBE, 0x32, 0xD7, 0x50, 0x0A, 0x88, 0xAD, 0x95, 0xD0, 0xDE, 0x2E, 0x55, 0x06, 0x1F, 0xB7, 0x43, 0x51, 0xB9, 0x5B, 0xBF, 0x3B, 0x8A, 0x69, 0xC3, 0x95, 0xC7, 0xB9, 0xC2, 0xC3, 0x13, 0xF3, 0xAD, 0x17, 0xAD, 0x02, 0x02, 0x42, 0xE6, 0x44, 0x9F, 0x8C, 0x99, 0x17, 0xC9, 0x18, 0x52, 0xF0, 0x14, 0x7B, 0x62, 0x4E, 0x6F, 0x3C, 0x18, 0x04, 0xBE, 0x42, 0xF6, 0x23, 0xF3, 0x32, 0x5F, 0x24, 0x1F, 0xD8, 0xAD, 0x95, 0x19, 0xD2, 0xCD, 0x5D, 0xBC, 0xA5, 0xD6, 0x99, 0x0F, 0xF7, 0x9B, 0x7B, 0x77, 0xC7, 0x64, 0xDF, 0x3A, 0xB3, 0xAB, 0x51, 0x3A, 0x16, 0xA0, 0x0A, 0x3C, 0xAC, 0x6D, 0x6D, 0x5F, 0x6F, 0x21, 0x5F, 0x99, 0x4E, 0xF1, 0xAC, 0x20, 0xE7, 0xF1, 0x04, 0x4E, 0x24, 0x02, 0x50, 0xC8, 0xF4, 0x1A, 0x0B, 0x98, 0x15, 0x8E, 0x1C, 0xE7, 0xB4, 0xA3, 0x66, 0x7F, 0xCB, 0x70, 0x52, 0x10, 0x8D, 0x72, 0xE5, 0xD6, 0x63, 0xD0, 0xE7, 0x5E, 0x2B, 0x7E, 0x98, 0x24, 0x52, 0x40, 0x6C, 0xC3, 0xAE, 0x7B, 0x46, 0x5C, 0xAE, 0x4A, 0x8D, 0xCD, 0xC6, 0x87, 0x70, 0x4B, 0x26, 0xF9, 0x05, 0x9F, 0x5D, 0x54, 0x47, 0xA3, 0x27, 0xFB, 0xB0, 0x82, 0x33, 0xE6, 0x5F, 0xCF, 0x51, 0xA3, 0x23, 0x3E, 0x2E, 0xF1, 0xFC, 0x42, 0xC4, 0x7D, 0xF6, 0x24, 0xB2, 0x5B, 0xC8, 0xDE, 0x80, 0xDE, 0x10, 0xEC, 0x61, 0x2C, 0x1F, 0xE1, 0x16, 0x55, 0xCF, 0xC4, 0xB2, 0x9A, 0x00, 0x61, 0xAF, 0xE7, 0x50, 0x25, 0x66, 0x35, 0xB0, 0x66, 0x68, 0xF7, 0xC8, 0xF2, 0x61, 0xEF, 0x04, 0xA4, 0xFB, 0x22, 0x5F, 0xC1, 0x4A, 0x4F, 0x84, 0x06, 0xEC, 0x12, 0x8E, 0x03, 0xA6, 0x1E, 0x0E, 0xEE, 0x40, 0xCA, 0xFA, 0xA8, 0x2D, 0xFB, 0x3B, 0x06, 0x58, 0x4E, 0x2D, 0x81, 0x29, 0xB7, 0x6F, 0x50, 0x9F, 0xE7, 0xB6, 0x18, 0x9A, 0x76, 0x4A, 0x5B, 0x43, 0x0E, 0xD7, 0xFB, 0xD4, 0xE5, 0xBB, 0x07, 0x61, 0x3B, 0x18, 0x4E, 0x43, 0xC4, 0x5B, 0xB0, 0x5F, 0xE2, 0x38, 0x68, 0x9C, 0x63, 0x04, 0xB4, 0x8A, 0x64, 0x28, 0x9E, 0x67, 0x9D, 0xF7, 0x90, 0xC1, 0xBB, 0xB0, 0x2B, 0xC5, 0xD3, 0x19, 0x52, 0x0E, 0x3D, 0x66, 0x8F, 0x9B, 0x23, 0xC9, 0xD5, 0x79, 0xA9, 0x30, 0x31, 0xC1, 0xA9, 0x33, 0x14, 0x9C, 0x35, 0x49, 0x4F, 0x1C, 0x58, 0xC2, 0x9D, 0x03, 0xC9, 0x1D, 0xE8, 0x97, 0xAD, 0x6B, 0x9C, 0x02, 0xC1, 0x82, 0x33, 0xCF, 0x4B, 0x70, 0x32, 0x56, 0x48, 0x6A, 0x7B, 0x22, 0x9B, 0x9C, 0x7B, 0x11, 0xE5, 0x40, 0x4A, 0xCD, 0x52, 0x45, 0x95, 0xF6, 0xE3, 0x3C, 0xE3, 0x93, 0x6E, 0x25, 0xD6, 0x0C, 0xF0, 0x5A, 0xC0, 0x98, 0xC2, 0xF5, 0xCA, 0x30, 0x29, 0x23, 0x93, 0xA5, 0x0E, 0xE3, 0x4B, 0x7E, 0x8B, 0x52, 0xB4, 0x48, 0x83, 0x27, 0xFE, 0x9C, 0xE1, 0x1E, 0xC6, 0x3C, 0x66, 0x6D, 0xF4, 0xD2, 0x17, 0xB9, 0xEA, 0xD1, 0x0D, 0x52, 0x46, 0xC6, 0xE8, 0x18, 0x50, 0x51, 0x70, 0x73, 0xFC, 0x95, 0xE9, 0xC9, 0x73, 0xB1, 0xC5, 0x57, 0xDF, 0x49, 0x0B, 0xB2, 0x0B, 0x70, 0xD3, 0xD6, 0x4C, 0xD7, 0x38, 0xA1, 0xEC, 0xA3, 0xF3, 0xF2, 0x93, 0x43, 0xD5, 0x7C, 0xA1, 0x5D, 0xAF, 0xD5, 0x3E, 0xEC, 0x77, 0x08, 0x69, 0x5B, 0x3F, 0x17, 0xCA, 0x10, 0x07, 0x30, 0xB1, 0xC0, 0x0B, 0x2E, 0xE4, 0x6F, 0x08, 0xCB, 0xDE, 0x94, 0xAB, 0x33, 0x80, 0x65, 0x2F, 0xCE, 0x33, 0x5F, 0xC7, 0x20, 0xC6, 0xA5, 0xDE, 0x28, 0x72, 0xE5, 0xEC, 0x76, 0x4E, 0x43, 0x12, 0xA4, 0x2B, 0x30, 0x8A, 0x44, 0x21, 0x49, 0x98, 0x45, 0x51, 0x91, 0x2B, 0x53, 0x52, 0x76, 0xED, 0xC2, 0x32, 0x83, 0xBC, 0x92, 0x16, 0x53, 0xEC, 0x70, 0x6C, 0xC5, 0x01, 0x60, 0xF5, 0x6B, 0xBA, 0xED, 0xEC, 0xBD, 0xED, 0xA8, 0x39, 0x4E, 0xD4, 0x2B, 0xA9, 0xB3, 0xB5, 0xA6, 0x28, 0x17, 0xFB, 0xB9, 0xCC, 0xC4, 0x0D, 0xB0, 0x3B, 0x2E, 0x73, 0x42, 0xDA, 0xE7, 0x40, 0x89, 0x58, 0x6A, 0xB9, 0x98, 0x00, 0xC8, 0xCD, 0x73, 0x49, 0x38, 0x1D, 0xC8, 0x19, 0x71, 0xCE, 0xBA, 0x09, 0x18, 0x9E, 0x86, 0xD4, 0xAA, 0x06, 0x71, 0x0F, 0x7C, 0x19, 0xF4, 0x9A, 0x9A, 0x58, 0xB2, 0x88, 0x2F, 0x18, 0x36, 0x72, 0xFC, 0x4D, 0x17, 0x49, 0x23, 0xD0, 0x63, 0xA8, 0x10, 0x37, 0x1F, 0x59, 0x98, 0xA0, 0x27, 0x87, 0x90, 0xD2, 0x5D, 0xBA, 0xBA, 0x6F, 0x87, 0xED, 0x48, 0x48, 0x98, 0xAA, 0x15, 0x8C, 0x36, 0xC7, 0xA4, 0xD5, 0x1E, 0x86, 0x25, 0x0F, 0x8F, 0x73, 0xD1, 0x9E, 0xD5, 0x9F, 0x7E, 0xB8, 0xAA, 0x85, 0x4F, 0x90, 0xB4, 0xBD, 0x53, 0x29, 0x70, 0xD0, 0xB3, 0x2A, 0x86, 0xDF, 0x8A, 0x38, 0x75, 0xE3, 0xFA, 0x3F, 0x04, 0x70, 0x5A, 0xC7, 0x4B, 0xF4, 0xF6, 0x4B, 0xB0, 0x73, 0x79, 0x51, 0x0F, 0x37, 0x37, 0xFE, 0x2F, 0xDF, 0xC2, 0x73, 0xD4, 0xC0, 0x9B, 0x3E, 0x37, 0x4D, 0xDE, 0xA4, 0x5F, 0xA4, 0x39, 0x4C, 0xE1, 0xF0, 0x81, 0xF0, 0xBB, 0x40, 0x1D, 0x99, 0x1E, 0x12, 0xDE, 0xD4, 0x24, 0x19, 0xE3, 0xE9, 0x8B, 0x14, 0xFC, 0x17, 0xA9, 0x7D, 0xA7, 0xFC, 0xF7, 0xA0, 0xBB, 0x57, 0x61, 0x7F, 0x79, 0x27, 0xCE, 0x51, 0xE0, 0xE9, 0x27, 0xE2, 0xBF, 0xD0, 0xDE, 0xBF, 0xD0, 0xDE, 0xEF, 0x42, 0x7B, 0x9D, 0xFB, 0xD9, 0x91, 0xED, 0x97, 0xD7, 0xFE, 0x10, 0x36, 0xF4, 0x40, 0x0C, 0x87, 0x13, 0xE0, 0x71, 0xAB, 0x33, 0xEA, 0x7A, 0x4D, 0x4F, 0x19, 0x74, 0x2E, 0xB7, 0xA7, 0x5C, 0x6B, 0xFA, 0x2D, 0x1D, 0xC4, 0x9E, 0xDF, 0x86, 0xC1, 0x83, 0xF4, 0x52, 0xF0, 0x48, 0x10, 0xA3, 0xBA, 0xFB, 0x6C, 0xD0, 0x8F, 0x1C, 0xEE, 0xBA, 0x73, 0x65, 0x1C, 0xC8, 0x44, 0xA7, 0xC8, 0xDD, 0x3F, 0x50, 0x05, 0xAF, 0x92, 0xD9, 0xCD, 0x87, 0x0E, 0xF3, 0xC0, 0xD2, 0x7C, 0x5E, 0xD1, 0x54, 0x69, 0xF4, 0x53, 0x15, 0x57, 0x72, 0xFF, 0xB4, 0x33, 0x72, 0x68, 0xC2, 0xEB, 0xC6, 0xDD, 0x4B, 0x6D, 0x86, 0x3B, 0xF4, 0x92, 0xFA, 0x94, 0xF8, 0xB8, 0xE0, 0x18, 0x1A, 0x9C, 0x57, 0x22, 0x01, 0x9C, 0x19, 0x6F, 0x1A, 0x04, 0x71, 0x14, 0xF4, 0x00, 0x47, 0xF1, 0xF8, 0xE4, 0x00, 0x92, 0x7D, 0x2C, 0xE8, 0xF3, 0xC8, 0x44, 0x91, 0x50, 0x77, 0x3F, 0xEC, 0x50, 0x52, 0x3D, 0x77, 0x28, 0xFF, 0x84, 0x45, 0xDB, 0x0B, 0xE5, 0xA7, 0xBF, 0xD4, 0xE5, 0xD4, 0x77, 0xB2, 0x09, 0xFA, 0x72, 0xB1, 0x74, 0xD0, 0x74, 0x38, 0x80, 0xC4, 0x12, 0xCF, 0x9D, 0x8E, 0x48, 0x97, 0xC1, 0x72, 0xCE, 0xE5, 0x79, 0xDB, 0xDC, 0x28, 0x51, 0xE8, 0x45, 0xB8, 0xB8, 0x57, 0xEF, 0x8E, 0x4A, 0xB0, 0xDD, 0x3F, 0x5B, 0xC7, 0x40, 0x51, 0xFF, 0x4A, 0x80, 0x63, 0xDD, 0x22, 0x56, 0x5F, 0xEF, 0xAD, 0xE9, 0xAC, 0x9C, 0x27, 0xCE, 0x3E, 0x4C, 0x2E, 0x41, 0x52, 0x34, 0xE0, 0xE2, 0x9C, 0x74, 0x83, 0x27, 0x4E, 0x77, 0xD6, 0xEE, 0xCF, 0x60, 0x22, 0xAF, 0x0A, 0x5B, 0x5D, 0x87, 0x18, 0x9F, 0x98, 0x2D, 0x0F, 0x2B, 0xB0, 0x28, 0xC7, 0x1A, 0x47, 0xD5, 0xAC, 0x96, 0x26, 0xE2, 0x64, 0xC5, 0x14, 0xBC, 0xAA, 0xE0, 0xE3, 0x6C, 0x9C, 0x74, 0x8F, 0x40, 0x6C, 0xD6, 0x51, 0xC0, 0x60, 0x4B, 0xCE, 0x09, 0x51, 0x88, 0xA4, 0x0B, 0x8C, 0xC8, 0x0E, 0xCD, 0x5D, 0xD0, 0x1D, 0x7E, 0xD2, 0xE6, 0x5C, 0xD2, 0xA1, 0xA1, 0xF9, 0x01, 0x97, 0x4F, 0x73, 0x93, 0x4C, 0x54, 0x00, 0xC6, 0x7B, 0xC5, 0x21, 0x04, 0x73, 0xC9, 0x47, 0x99, 0xB8, 0x16, 0x19, 0x6F, 0xB1, 0xC0, 0xCC, 0x59, 0xD5, 0xF3, 0xCE, 0x2D, 0x75, 0xB3, 0xBC, 0x3E, 0xC3, 0x5B, 0x67, 0xAC, 0x8F, 0x2D, 0xCE, 0x16, 0xA8, 0x30, 0x7C, 0x2E, 0xA0, 0xA4, 0x64, 0xB9, 0x65, 0x18, 0xCD, 0x7D, 0x02, 0x55, 0x7C, 0xAB, 0x88, 0xDE, 0xA8, 0xF9, 0x98, 0x72, 0xF5, 0x66, 0xEB, 0x1F, 0x05, 0x6C, 0xC3, 0x9E, 0xAD, 0x09, 0x7D, 0x76, 0xF4, 0xA2, 0xF3, 0x1E, 0x49, 0x50, 0xDF, 0xEE, 0xD7, 0xBD, 0xE5, 0xE9, 0xC3, 0xBC, 0x2E, 0x12, 0xBC, 0xE1, 0xD8, 0x1A, 0x76, 0xE5, 0x52, 0x4E, 0x1D, 0x84, 0xB3, 0xB0, 0xC7, 0x32, 0xE6, 0x78, 0x38, 0x32, 0x34, 0x76, 0x22, 0x69, 0xFE, 0x2A, 0x92, 0x23, 0x7E, 0xA3, 0x46, 0x3E, 0x67, 0x3C, 0x26, 0x78, 0xC4, 0xF7, 0x42, 0x66, 0x9E, 0x38, 0x58, 0xAD, 0x26, 0xC9, 0x9A, 0x81, 0x6D, 0x85, 0xDE, 0x4D, 0x31, 0xA6, 0xC1, 0x57, 0x23, 0x3F, 0xE2, 0x6E, 0x83, 0x8F, 0x80, 0x77, 0xD8, 0x9A, 0x22, 0x2F, 0xC7, 0xEF, 0x64, 0xD8, 0x4E, 0xAF, 0xF7, 0x9D, 0x72, 0xDA, 0x19, 0x26, 0xC1, 0xBB, 0x58, 0xA7, 0xCC, 0x69, 0x5F, 0x2E, 0x20, 0xD5, 0xE6, 0xAE, 0x48, 0x84, 0x14, 0x36, 0x4E, 0x2E, 0x39, 0x77, 0xA1, 0x6C, 0x2E, 0xE4, 0x26, 0xC4, 0x2B, 0xC5, 0x90, 0x0D, 0x72, 0x59, 0x10, 0x09, 0xD2, 0xA1, 0x7C, 0xB0, 0xA7, 0x22, 0xE2, 0xAF, 0x40, 0xEF, 0x36, 0x0C, 0x7F, 0xF6, 0x7D, 0x2B, 0xC4, 0xD4, 0x3B, 0xBF, 0x11, 0x8D, 0x7C, 0xCB, 0x5C, 0xE9, 0x44, 0xEE, 0x38, 0x91, 0x14, 0xA0, 0x22, 0x10, 0x6A, 0x69, 0xB6, 0x5E, 0x79, 0x2B, 0x0F, 0xE8, 0x3D, 0xD3, 0xD7, 0xEC, 0xBE, 0x30, 0x6A, 0x7D, 0xF3, 0xF0, 0xD3, 0x7A, 0xF5, 0xF1, 0xC0, 0xB4, 0x1E, 0xBB, 0xB4, 0x8B, 0xAD, 0x43, 0x6D, 0xCF, 0x70, 0xC2, 0x47, 0x15, 0xB6, 0x58, 0x92, 0x55, 0xEC, 0xF6, 0xCA, 0xF1, 0xE6, 0x81, 0x6E, 0xDD, 0xAB, 0xDA, 0x4B, 0x79, 0x97, 0xE1, 0xAC, 0x83, 0x97, 0x93, 0xAB, 0x86, 0x28, 0x45, 0xB3, 0xCF, 0xBB, 0xDC, 0x4A, 0xD7, 0x81, 0xC4, 0xC1, 0x28, 0xB2, 0xB2, 0xD7, 0xF9, 0xEC, 0xCD, 0x66, 0x3C, 0x3C, 0x63, 0x12, 0xB0, 0xA9, 0x8B, 0x1D, 0xD9, 0xB6, 0x6F, 0x51, 0x78, 0xB8, 0xF1, 0xE6, 0xE1, 0x9E, 0xF9, 0x4D, 0x11, 0xA5, 0xBA, 0xC0, 0x50, 0x79, 0x6D, 0xE6, 0xB4, 0xE0, 0xF2, 0x4C, 0x67, 0x8A, 0x77, 0x06, 0x5B, 0x24, 0x6B, 0xC6, 0x17, 0x71, 0x56, 0x26, 0x28, 0x34, 0x25, 0x18, 0xC0, 0xE0, 0x14, 0xDE, 0x8B, 0xF1, 0xB2, 0x21, 0xD0, 0x7D, 0x4B, 0xAB, 0x87, 0xD2, 0x1F, 0x30, 0x74, 0xBC, 0x11, 0x16, 0x2E, 0xC5, 0xBC, 0x42, 0x0A, 0x96, 0x9D, 0xE2, 0x11, 0x76, 0xB4, 0xC4, 0x49, 0x77, 0x77, 0x69, 0x2C, 0x1C, 0x91, 0xEC, 0xBD, 0x69, 0x43, 0xD8, 0x44, 0xD6, 0xA2, 0xCC, 0x83, 0xB4, 0xB5, 0xF4, 0xBD, 0x15, 0xF5, 0xE8, 0xEA, 0x9C, 0x0E, 0xDC, 0x9A, 0x0A, 0xBE, 0xC3, 0x3E, 0x04, 0x6F, 0x66, 0x6F, 0xDC, 0x75, 0x4D, 0xA5, 0x8D, 0x02, 0xEE, 0x46, 0xE1, 0xAD, 0x35, 0xD3, 0x62, 0x75, 0x62, 0xA7, 0x66, 0x14, 0x77, 0xD4, 0xF3, 0xC4, 0xB4, 0x91, 0x56, 0xEA, 0x03, 0x37, 0xB8, 0xDA, 0x43, 0x53, 0x22, 0xC3, 0x9D, 0x40, 0xFE, 0x94, 0xC0, 0x27, 0x84, 0xA8, 0x4B, 0x8E, 0x1E, 0x9F, 0x17, 0xC2, 0x3A, 0xA5, 0xB7, 0x14, 0xEA, 0xA4, 0xC3, 0x7F, 0xF5, 0xDD, 0x00, 0x9A, 0xDB, 0x75, 0x7D, 0x46, 0x53, 0xB0, 0x15, 0x91, 0x7C, 0xD6, 0xE0, 0xE7, 0x96, 0xDE, 0xB2, 0x1A, 0x24, 0xB5, 0x07, 0xEB, 0xB2, 0x64, 0x4A, 0x31, 0xC5, 0xB0, 0xB9, 0xA8, 0xB4, 0x85, 0x01, 0x57, 0x25, 0x25, 0x16, 0x87, 0x5B, 0x22, 0xDF, 0x57, 0x32, 0xE5, 0x07, 0x71, 0x3D, 0xFE, 0x55, 0xAB, 0xDF, 0xAF, 0xB2, 0x73, 0xDB, 0xCB, 0xF6, 0x84, 0x40, 0x42, 0xE2, 0x1C, 0x69, 0xC1, 0x98, 0x63, 0x14, 0xA4, 0xB9, 0x31, 0xBD, 0xCB, 0xAE, 0x3A, 0x7D, 0xF7, 0x4F, 0x5E, 0x19, 0xC1, 0xB2, 0x29, 0xA4, 0x6B, 0x8F, 0x04, 0x06, 0xA7, 0x15, 0x21, 0x69, 0x9C, 0x75, 0x20, 0xF2, 0x46, 0x72, 0x0A, 0x65, 0x1E, 0x93, 0xBA, 0x93, 0xA0, 0x91, 0xA1, 0xAD, 0xC9, 0x1A, 0xC4, 0x1C, 0x0F, 0x31, 0x55, 0xB1, 0x49, 0xE1, 0xD2, 0x34, 0x09, 0x87, 0x2A, 0xE7, 0x0D, 0x8E, 0x6C, 0xF1, 0x26, 0x90, 0x2A, 0x86, 0xBD, 0x64, 0xA2, 0xCC, 0x52, 0xF6, 0x31, 0x36, 0x06, 0x3E, 0x43, 0x42, 0x33, 0x07, 0x65, 0x9D, 0xED, 0xF0, 0xE7, 0x2C, 0x8B, 0x71, 0xD4, 0x6D, 0x6E, 0xDB, 0x13, 0x3D, 0x45, 0xDB, 0xE6, 0xA9, 0xA2, 0x58, 0xF9, 0x04, 0x2A, 0xEE, 0xC9, 0x2C, 0x9E, 0xC0, 0xBC, 0x21, 0x1D, 0xF9, 0xDE, 0x35, 0x5D, 0xA6, 0x3E, 0x0F, 0x1F, 0xEF, 0xA1, 0x8F, 0xC9, 0xBD, 0x05, 0x9A, 0xFB, 0x50, 0x57, 0xE5, 0x64, 0xAD, 0x00, 0x86, 0x53, 0x0A, 0x5C, 0xAC, 0x4F, 0x52, 0xA4, 0xF4, 0x06, 0x83, 0x6D, 0xB6, 0x5B, 0xD6, 0x9A, 0x5A, 0x4E, 0xED, 0x09, 0xBE, 0x8F, 0x75, 0x31, 0xED, 0x4B, 0x16, 0x44, 0x08, 0x81, 0x11, 0xAF, 0xB3, 0xF3, 0x35, 0xD2, 0x88, 0xCF, 0x93, 0xA5, 0x58, 0xDA, 0xD2, 0x38, 0x8C, 0x2D, 0x3D, 0x33, 0x2E, 0x51, 0x34, 0xFD, 0xC0, 0xBA, 0xD9, 0x13, 0xB2, 0x97, 0x9E, 0x5B, 0x7C, 0x75, 0x4C, 0x38, 0xFA, 0xBC, 0xDE, 0x97, 0xA0, 0x7B, 0xA0, 0xA0, 0xD2, 0x03, 0x34, 0x75, 0xCE, 0xA3, 0xF0, 0xB2, 0x04, 0xF1, 0x81, 0x08, 0x43, 0x57, 0x02, 0x9E, 0x1D, 0x1C, 0x88, 0x14, 0xFC, 0x38, 0x77, 0x36, 0xC2, 0xEE, 0x85, 0x01, 0xEA, 0x49, 0x71, 0xE9, 0xCA, 0xA2, 0xA2, 0xD4, 0xB2, 0xA5, 0xE9, 0x64, 0x72, 0xA1, 0x1B, 0xF2, 0x3C, 0x80, 0xA3, 0x67, 0x7B, 0xB7, 0x4E, 0x7A, 0xE2, 0x0B, 0xEA, 0xA2, 0x0A, 0x3B, 0xF5, 0xCB, 0x90, 0xBE, 0xEE, 0x9C, 0x08, 0xD2, 0x18, 0x80, 0xE0, 0x18, 0x4F, 0x53, 0x86, 0xCD, 0x98, 0x43, 0x3D, 0x0A, 0x4E, 0xAA, 0x6E, 0x7C, 0x2F, 0x90, 0x51, 0x19, 0x00, 0xBE, 0x6D, 0xD2, 0xDB, 0x2A, 0x2B, 0x88, 0x70, 0xB6, 0x2F, 0x9B, 0xD6, 0x00, 0xF1, 0x1E, 0x93, 0xF8, 0xED, 0x21, 0xFA, 0x15, 0xB1, 0x0D, 0x24, 0xDF, 0x2B, 0xB7, 0xEA, 0x32, 0x92, 0x90, 0xC3, 0x66, 0x56, 0x40, 0x88, 0xF3, 0x13, 0xE6, 0xB2, 0x48, 0x1B, 0x52, 0xC1, 0xBB, 0x66, 0x85, 0xB6, 0xB6, 0xD7, 0x21, 0x4F, 0x87, 0x70, 0x73, 0x91, 0xC3, 0xF5, 0xA6, 0x17, 0x88, 0x77, 0x07, 0xCF, 0x42, 0x57, 0x44, 0xD9, 0xF5, 0xE0, 0xD1, 0x8E, 0x61, 0x3D, 0x19, 0xB1, 0x62, 0x93, 0x06, 0x1F, 0x32, 0x24, 0xDE, 0x41, 0x36, 0x0C, 0xB3, 0xD5, 0x5D, 0xBB, 0xCF, 0x7C, 0xB6, 0x2D, 0x3A, 0x57, 0x8B, 0xD8, 0xBE, 0xBB, 0x19, 0x2A, 0x5E, 0x0F, 0x44, 0xBF, 0x1E, 0xD2, 0xB7, 0x61, 0x5E, 0x50, 0x2C, 0xD6, 0x05, 0x2A, 0x31, 0xF7, 0x01, 0x87, 0x25, 0x8F, 0x8E, 0x92, 0xC8, 0xC1, 0x49, 0xF4, 0x7C, 0x5D, 0x3D, 0xCA, 0x99, 0x0B, 0xD7, 0xE2, 0xA7, 0xCC, 0x57, 0xCE, 0xC4, 0x31, 0x62, 0xAF, 0x4C, 0x03, 0x9F, 0xA0, 0x2E, 0xAC, 0xD3, 0x69, 0xD5, 0x78, 0xA8, 0xE0, 0x4B, 0x6C, 0x98, 0xD0, 0x6E, 0xB9, 0x6E, 0xD6, 0x6E, 0xC7, 0x37, 0xFB, 0x89, 0xF4, 0x04, 0xAE, 0x5C, 0xD0, 0xFB, 0x55, 0x73, 0xF9, 0x5B, 0x13, 0x4D, 0xB6, 0x25, 0xED, 0xB6, 0x1D, 0x91, 0xD3, 0x4D, 0x93, 0xE4, 0x53, 0x5F, 0x26, 0x27, 0x5E, 0xE3, 0xC8, 0x19, 0xC0, 0x47, 0x57, 0xBF, 0xDE, 0x83, 0xA4, 0x67, 0x35, 0x3C, 0xA5, 0xF3, 0x4B, 0x2F, 0xB7, 0xFC, 0x79, 0x27, 0xB1, 0xB0, 0xAA, 0x9B, 0xBB, 0xA3, 0xAB, 0x3D, 0xB1, 0x44, 0xE6, 0x63, 0xF4, 0x66, 0xC7, 0xE0, 0x51, 0x53, 0x49, 0xB6, 0x6D, 0x13, 0xAE, 0x45, 0x64, 0x1B, 0x45, 0x31, 0xE6, 0x34, 0x3E, 0xEB, 0xD4, 0x5D, 0x38, 0x6A, 0xE6, 0xD0, 0xD3, 0xD3, 0xE9, 0x70, 0xFE, 0x3C, 0xAB, 0xB8, 0x5B, 0x3D, 0xFF, 0x7C, 0xA2, 0x5C, 0x5A, 0xA0, 0x7D, 0xD8, 0x2C, 0xC7, 0x58, 0xB4, 0xF6, 0x5E, 0x0D, 0x1E, 0x65, 0x09, 0xDB, 0x1D, 0x95, 0xE2, 0x15, 0x11, 0x3A, 0xF7, 0xF9, 0x8C, 0xFC, 0xA4, 0x98, 0x19, 0xE7, 0x71, 0x91, 0xF2, 0xA1, 0xAC, 0xB7, 0xF4, 0x22, 0x37, 0xD3, 0x70, 0xE8, 0xBF, 0x36, 0xA3, 0xF0, 0xA0, 0x9C, 0x87, 0x2A, 0x56, 0xF6, 0x05, 0xB5, 0x1B, 0x24, 0x4A, 0xCE, 0x4A, 0xEC, 0xC4, 0x8D, 0x55, 0x6F, 0x0F, 0xD5, 0x38, 0xC5, 0x9D, 0x13, 0xB1, 0x67, 0x7E, 0xE8, 0x4D, 0x51, 0x39, 0x9F, 0x4E, 0x18, 0x2C, 0xCA, 0xF5, 0x15, 0xC9, 0x30, 0x67, 0x77, 0xB8, 0x23, 0xBF, 0xED, 0x25, 0xEB, 0x1E, 0xF3, 0xB8, 0x52, 0x39, 0x30, 0x07, 0xDB, 0xE4, 0xDC, 0x46, 0x04, 0x0B, 0x73, 0xD7, 0x18, 0x9E, 0x36, 0xBC, 0x9E, 0x0E, 0x8B, 0x20, 0xF2, 0xAC, 0x53, 0xEE, 0x55, 0xEF, 0xEC, 0x27, 0xE8, 0xAA, 0x16, 0x3B, 0x2A, 0x4C, 0xB2, 0xA0, 0x1C, 0x3A, 0x29, 0xAD, 0x6B, 0x0F, 0x04, 0x07, 0x0E, 0x16, 0x17, 0x54, 0xDF, 0xD6, 0x50, 0x45, 0xD4, 0x61, 0x4B, 0x32, 0x52, 0x4E, 0xDD, 0x23, 0x21, 0x28, 0x35, 0x07, 0x1E, 0x5F, 0x1F, 0xF5, 0x7C, 0x5E, 0x04, 0x9E, 0x11, 0x72, 0x35, 0xC7, 0x32, 0x50, 0xBA, 0x3F, 0xEF, 0x88, 0x09, 0x9D, 0x8B, 0xF1, 0x14, 0x82, 0x95, 0xA4, 0xA0, 0xE6, 0xB4, 0x94, 0xBA, 0xBB, 0x38, 0xB8, 0x26, 0xF0, 0x1B, 0x90, 0xDC, 0x0B, 0x1A, 0x3A, 0x55, 0x5D, 0x00, 0x5C, 0x6E, 0x10, 0x24, 0x35, 0x9D, 0xAA, 0xAE, 0xE9, 0x75, 0x69, 0xB2, 0xC4, 0x95, 0x9C, 0x22, 0xE7, 0xAE, 0x75, 0xB0, 0xE0, 0x42, 0x77, 0xB4, 0x93, 0x6B, 0xAB, 0x24, 0x29, 0x71, 0xA8, 0x67, 0xF5, 0x05, 0x83, 0x9B, 0x3E, 0xBE, 0xAD, 0x99, 0xB4, 0xE4, 0x47, 0xC6, 0xEC, 0xBB, 0x2B, 0x96, 0xBB, 0x4F, 0x10, 0x11, 0xCB, 0x48, 0xF0, 0x33, 0x26, 0x34, 0x79, 0xC2, 0x2F, 0x1B, 0xBB, 0x9D, 0xCD, 0xA9, 0x34, 0xD3, 0x47, 0x81, 0xCE, 0x2A, 0x97, 0xC5, 0xED, 0x79, 0xBE, 0xD4, 0x30, 0xB2, 0x8D, 0x94, 0x70, 0x65, 0xE9, 0x60, 0xB1, 0xD3, 0x7C, 0x17, 0x2C, 0xE5, 0x71, 0x6F, 0x5D, 0xB9, 0xE5, 0x62, 0xA3, 0x1F, 0x56, 0x40, 0x39, 0x5C, 0x84, 0xA9, 0x2E, 0x8A, 0x3E, 0x11, 0x83, 0xD0, 0x09, 0xF8, 0x7E, 0x4E, 0x20, 0x5A, 0x6D, 0x84, 0x0B, 0x75, 0xE2, 0x96, 0x4B, 0xE4, 0xD4, 0x91, 0x7A, 0x97, 0xF7, 0x47, 0x34, 0x35, 0x69, 0x76, 0x5B, 0xEE, 0x4A, 0x1E, 0xE9, 0x10, 0xC0, 0x20, 0x50, 0xB5, 0xBB, 0xDE, 0x29, 0x85, 0x94, 0xD4, 0x44, 0x90, 0xC9, 0xAE, 0x2F, 0xC7, 0x30, 0xE8, 0xF4, 0x47, 0x5C, 0x4C, 0x02, 0x98, 0x2D, 0x66, 0x29, 0x7F, 0xEF, 0x36, 0xF8, 0x54, 0x25, 0x55, 0x50, 0x86, 0x4C, 0x8F, 0x64, 0x77, 0x89, 0xF2, 0x9B, 0x29, 0x30, 0x27, 0xE3, 0x0E, 0x6E, 0xF8, 0xE3, 0xC0, 0xB4, 0xE0, 0x30, 0x65, 0x05, 0x11, 0x45, 0x03, 0x71, 0xBE, 0xB4, 0x82, 0xB5, 0x03, 0x50, 0x72, 0x53, 0xC2, 0x24, 0xA6, 0x6C, 0x0B, 0xB8, 0xA0, 0x7E, 0x63, 0x4C, 0x38, 0x5A, 0x60, 0xDD, 0xAD, 0xF6, 0x35, 0xF7, 0x72, 0x8D, 0x8E, 0x04, 0xEE, 0x89, 0x7A, 0x83, 0xEA, 0xDC, 0x33, 0xDA, 0x50, 0x44, 0x13, 0xAA, 0x25, 0x00, 0x71, 0x44, 0x35, 0x1C, 0x97, 0x44, 0x04, 0x9C, 0xB0, 0x54, 0x41, 0x23, 0xC0, 0x38, 0xD3, 0xBD, 0x1B, 0x2C, 0x62, 0xFB, 0x08, 0x86, 0x40, 0x83, 0xF2, 0x79, 0x6B, 0x77, 0xB9, 0x8D, 0xB3, 0x6D, 0x45, 0x86, 0x49, 0xDA, 0x4E, 0xAD, 0xE7, 0xA8, 0x2E, 0xDC, 0xE4, 0xDD, 0x72, 0xE3, 0xFC, 0x3D, 0x05, 0xB1, 0x6C, 0x0D, 0x8D, 0x61, 0xDE, 0xEA, 0x25, 0x06, 0x9C, 0x09, 0x2A, 0xEF, 0x9B, 0x4A, 0x6A, 0x96, 0x7A, 0xCF, 0xE3, 0x86, 0x37, 0x7B, 0xFE, 0x6A, 0x3E, 0xA6, 0xF1, 0x2C, 0xEB, 0xEB, 0x58, 0xF0, 0xB1, 0x79, 0x35, 0x25, 0x64, 0xEE, 0x2D, 0xCE, 0x12, 0xB3, 0xD1, 0xBE, 0x07, 0x19, 0x72, 0x18, 0x18, 0x0C, 0x08, 0x6A, 0xAF, 0x2E, 0xDC, 0xA0, 0x05, 0x10, 0x3D, 0x94, 0xEE, 0x96, 0x48, 0x86, 0x9C, 0x87, 0x48, 0x21, 0x3A, 0x05, 0x2A, 0xF4, 0xD0, 0xC0, 0xD1, 0x04, 0x2C, 0xD1, 0x85, 0x03, 0x0B, 0xF6, 0x4C, 0x75, 0xA5, 0x39, 0x42, 0x5A, 0x2B, 0xDA, 0xED, 0xB6, 0x8B, 0x9C, 0x09, 0x6E, 0x06, 0x79, 0x3A, 0x12, 0x48, 0x3C, 0x13, 0x71, 0xA4, 0xA8, 0x09, 0xA1, 0x46, 0x3F, 0x63, 0x61, 0xD7, 0x8A, 0x0E, 0xBD, 0x89, 0x25, 0xD0, 0x9E, 0x86, 0x95, 0x6C, 0x30, 0x82, 0x56, 0xF2, 0xCD, 0x23, 0x0A, 0xAC, 0x67, 0x9F, 0x23, 0xF3, 0x10, 0x4D, 0xB9, 0x79, 0x9E, 0x30, 0x23, 0x7F, 0xD6, 0x1C, 0x86, 0x23, 0x45, 0x95, 0x8E, 0xFB, 0xC4, 0x6A, 0x5A, 0xAE, 0x7A, 0x17, 0xE1, 0xC9, 0xCF, 0xFA, 0xDA, 0x07, 0x08, 0x32, 0x00, 0x17, 0x1C, 0x87, 0x68, 0x13, 0xCD, 0x45, 0x5C, 0xD0, 0xAB, 0x03, 0x88, 0xCD, 0xC6, 0xED, 0x89, 0x81, 0x7A, 0x34, 0xE1, 0x46, 0x1E, 0xAE, 0x22, 0x6E, 0xA3, 0x53, 0xA2, 0x0D, 0x8B, 0xBB, 0xDD, 0x1F, 0x88, 0x51, 0xF9, 0xBA, 0x15, 0xA1, 0xE0, 0x84, 0x5E, 0x12, 0x93, 0xA2, 0x21, 0x1C, 0x3B, 0x9C, 0xA9, 0xC7, 0xD5, 0x64, 0x3B, 0xFB, 0xC2, 0xD7, 0x9C, 0xAA, 0xA1, 0x0A, 0xA2, 0xC2, 0x97, 0xFB, 0x35, 0x32, 0x2B, 0x33, 0x3D, 0x3D, 0x0A, 0x7D, 0x53, 0xA7, 0x05, 0x52, 0x45, 0x1A, 0x9F, 0xA6, 0x40, 0xA9, 0x2F, 0x34, 0xD6, 0x3B, 0xA3, 0xFB, 0x3C, 0x2C, 0x54, 0x19, 0x9B, 0xF4, 0xD5, 0x34, 0x05, 0x05, 0x03, 0xB2, 0x2E, 0x36, 0x09, 0xCF, 0x36, 0x2B, 0x96, 0x0A, 0x2A, 0xCF, 0xE4, 0x9A, 0x49, 0xF2, 0x91, 0x30, 0x1E, 0x4A, 0x31, 0x96, 0x6C, 0xC4, 0x03, 0xE7, 0x4C, 0x69, 0x8B, 0x2B, 0x7A, 0xF6, 0xC6, 0xBE, 0xE7, 0x50, 0x7F, 0x64, 0x97, 0x3B, 0x53, 0xBE, 0x1C, 0x1F, 0x85, 0x1B, 0xCC, 0xDC, 0xED, 0x5A, 0x4E, 0x31, 0xDB, 0xA2, 0x90, 0x05, 0x58, 0x3F, 0x0A, 0x63, 0x30, 0xE6, 0xB5, 0x22, 0x89, 0x51, 0xA0, 0xAF, 0x6D, 0x2B, 0xC4, 0xD0, 0xA5, 0xBF, 0xEC, 0x2E, 0xC5, 0xDC, 0x4A, 0x76, 0xD8, 0xF6, 0xCA, 0xB7, 0xAB, 0x5E, 0xF0, 0x50, 0xE3, 0x56, 0x7A, 0xE6, 0xA9, 0x37, 0x90, 0xDC, 0xAC, 0x6F, 0x72, 0xBA, 0x5A, 0x22, 0xCB, 0x74, 0x8C, 0x47, 0x51, 0xF7, 0xDB, 0x42, 0x65, 0x3B, 0x1A, 0x31, 0x55, 0x0B, 0x94, 0xD1, 0x64, 0xE6, 0xC4, 0xA0, 0xC8, 0xB8, 0x79, 0xC3, 0xC8, 0xE4, 0xB0, 0xD0, 0x69, 0xCD, 0x92, 0x4B, 0x4A, 0x27, 0xCB, 0x4A, 0xF1, 0x00, 0x7F, 0x8C, 0xAA, 0x12, 0xE7, 0x48, 0xFB, 0xFD, 0xC9, 0x09, 0xA1, 0xAF, 0x02, 0xAB, 0x16, 0xD5, 0x13, 0x52, 0x75, 0x0E, 0xE1, 0xE4, 0xB5, 0x3E, 0x79, 0x46, 0x12, 0x73, 0xE7, 0xAE, 0x02, 0x52, 0x58, 0x29, 0xFC, 0x68, 0xBB, 0x3D, 0x82, 0xF1, 0x6C, 0x93, 0x25, 0xEB, 0x04, 0x62, 0x1D, 0x5C, 0x9E, 0x72, 0x60, 0x03, 0xB3, 0x94, 0xB7, 0x8A, 0xCB, 0x9F, 0x79, 0x9C, 0x7F, 0x0C, 0xB6, 0xEB, 0x64, 0x03, 0xF5, 0x4C, 0xE1, 0x14, 0x79, 0x4E, 0xC0, 0x13, 0x51, 0x6D, 0x6E, 0x7E, 0x16, 0xB8, 0xD8, 0x87, 0x84, 0x79, 0x5A, 0xA9, 0x02, 0x97, 0x08, 0x0D, 0x98, 0x82, 0xBC, 0xB0, 0x4E, 0x2B, 0x5D, 0x5E, 0x2F, 0x19, 0x55, 0xD3, 0x63, 0xD0, 0x5E, 0x12, 0x4A, 0x36, 0x36, 0x21, 0x9D, 0xBC, 0xFD, 0x7E, 0x9D, 0x5B, 0xAA, 0x4A, 0xB5, 0xE7, 0x32, 0x45, 0x27, 0x66, 0xF4, 0x5A, 0x9A, 0xA4, 0x56, 0xFF, 0xA2, 0xEB, 0xAA, 0x10, 0xBA, 0xB8, 0x2E, 0xDB, 0x83, 0x2C, 0x05, 0x29, 0x91, 0x96, 0xA9, 0x34, 0x59, 0xC4, 0x15, 0xCE, 0x09, 0xB5, 0x70, 0x28, 0xF7, 0x44, 0x9F, 0x36, 0x0D, 0x9A, 0xC3, 0x87, 0x68, 0x95, 0xCF, 0x49, 0xD5, 0x8C, 0xB9, 0xB6, 0xB3, 0xEE, 0x62, 0x11, 0xE0, 0x2A, 0xC3, 0x5A, 0x38, 0xB3, 0x88, 0x4C, 0x1F, 0x30, 0x47, 0xA7, 0xEB, 0xA8, 0x0D, 0xD7, 0xCA, 0xC3, 0x12, 0xE6, 0x68, 0x88, 0x20, 0xC2, 0xC5, 0x7C, 0xA7, 0x26, 0xE6, 0x18, 0xB0, 0x7A, 0x48, 0x7D, 0x08, 0xE8, 0xC0, 0x12, 0x10, 0xF0, 0x00, 0x2E, 0x96, 0x81, 0x43, 0xC0, 0x6D, 0x49, 0xE4, 0x1B, 0x3E, 0x52, 0xD1, 0x9A, 0xF0, 0xA8, 0x75, 0xC5, 0x1E, 0xA8, 0x05, 0x4B, 0xC2, 0x08, 0x1E, 0xF6, 0xD8, 0x79, 0x8A, 0x5E, 0x15, 0xCF, 0x7E, 0xD7, 0xE6, 0x9B, 0x21, 0x93, 0x13, 0x8B, 0x50, 0x66, 0xCC, 0xD1, 0x74, 0x9B, 0xD7, 0xCB, 0x1C, 0xE8, 0x99, 0x37, 0xA2, 0x1C, 0x00, 0x59, 0x18, 0x1B, 0x24, 0x55, 0x1F, 0x3C, 0x3B, 0x9D, 0xF5, 0x41, 0xB3, 0x88, 0xD1, 0x1D, 0x0E, 0x0B, 0x67, 0x3A, 0xFC, 0xF5, 0x68, 0xEB, 0x81, 0xDE, 0x0F, 0x28, 0x01, 0xE1, 0x37, 0x46, 0x83, 0x00, 0xCE, 0xB2, 0x61, 0x33, 0x44, 0x25, 0xA1, 0x3E, 0xC3, 0xE9, 0xA2, 0xED, 0x42, 0xAF, 0x3C, 0x0E, 0xFE, 0xB1, 0x8C, 0x9E, 0x3A, 0xC7, 0x48, 0xEA, 0xF5, 0x82, 0x50, 0x85, 0x76, 0x26, 0xE1, 0xCB, 0x4D, 0x5C, 0x96, 0xCC, 0x79, 0x12, 0x22, 0xA5, 0xCC, 0xC5, 0x09, 0xB6, 0xA0, 0xFA, 0x75, 0x6E, 0xFE, 0x54, 0xA1, 0x84, 0xC1, 0xD9, 0x11, 0xF1, 0x0C, 0x97, 0x86, 0xA1, 0xC5, 0x59, 0x66, 0x51, 0x1B, 0x61, 0x1A, 0xD3, 0xD6, 0x8B, 0x05, 0xD5, 0xB4, 0x61, 0x4E, 0x51, 0x48, 0x51, 0xC1, 0xD5, 0x92, 0xF9, 0x4B, 0xCE, 0xB2, 0x57, 0x76, 0xE3, 0xDE, 0xAF, 0x4F, 0xA4, 0x04, 0xDD, 0xC4, 0x98, 0xA1, 0x14, 0xD2, 0x34, 0xFD, 0xDB, 0x2F, 0x6E, 0xCA, 0xBB, 0xB6, 0x4D, 0x92, 0xA7, 0xBF, 0x38, 0xC1, 0xF4, 0xDF, 0x3A, 0xC5, 0xF4, 0xBF, 0xFF, 0xD7, 0x1F, 0xFE, 0xF0, 0x87, 0xBF, 0x26, 0xED, 0x50, 0xBF, 0xF9, 0xE1, 0x94, 0xB7, 0xCD, 0xEB, 0x40, 0x98, 0xD7, 0x8C, 0xD2, 0x9A, 0x27, 0xF9, 0x77, 0x7F, 0x7F, 0x6C, 0x63, 0xD5, 0x1E, 0x00, 0xFB, 0xFD, 0xBC, 0xDB, 0x7F, 0x7F, 0xFB, 0x6B, 0xDE, 0x74, 0xF3, 0xF4, 0xF1, 0x8E, 0xCA, 0xD7, 0x2D, 0x9A, 0xDF, 0x7D, 0xF8, 0x0E, 0xFF, 0x1E, 0xEB, 0x1F, 0x1F, 0x62, 0x7D, 0xF7, 0xF1, 0xE2, 0xCC, 0x2F, 0x02, 0x17, 0xBF, 0x9A, 0x8F, 0xD0, 0xF7, 0x52, 0x83, 0x7F, 0x7F, 0x3C, 0x6E, 0xF4, 0x2F, 0x8A, 0x7B, 0x25, 0xFD, 0x8F, 0x71, 0xCC, 0xA3, 0x4F, 0xA2, 0x3E, 0x0B, 0xF8, 0xB9, 0x18, 0xCD, 0x1F, 0xC7, 0xB5, 0x1D, 0xA2, 0x2F, 0x44, 0x75, 0x1F, 0x83, 0x7F, 0xC6, 0xDF, 0x8D, 0xE5, 0x47, 0xAE, 0x9F, 0xC5, 0x1D, 0xE7, 0xA0, 0xCE, 0xA7, 0xD7, 0x64, 0xCD, 0xAB, 0x12, 0xFE, 0xFE, 0x87, 0x3F, 0xBC, 0xBD, 0x7D, 0x7D, 0x2A, 0xE9, 0x43, 0xE3, 0xBC, 0x6A, 0xEB, 0xFF, 0xD7, 0xA9, 0x9B, 0xE3, 0xE5, 0xF3, 0xAB, 0xFE, 0xC0, 0xF7, 0xBB, 0xFE, 0x3E, 0xBD, 0x75, 0x9F, 0x75, 0xE7, 0xBF, 0x82, 0xDD, 0x67, 0xC1, 0xFE, 0xC7, 0x4B, 0x4B, 0x5F, 0x17, 0xB3, 0x8E, 0xFF, 0x0E, 0x82, 0x69, 0x3E, 0x65, 0x73, 0xF0, 0x43, 0xD8, 0xD6, 0xA0, 0xFC, 0xBA, 0x52, 0x35, 0x1C, 0x72, 0xF0, 0x8B, 0xF3, 0x9F, 0xDF, 0x26, 0x7F, 0x48, 0xE3, 0x43, 0x55, 0xFE, 0x11, 0x54, 0x7E, 0x53, 0xFE, 0xB6, 0xAE, 0xFC, 0xDB, 0xE5, 0xFF, 0xD8, 0xA4, 0xFE, 0xDF, 0x7F, 0x6F, 0x56, 0xC1, 0xA0, 0x6A, 0x03, 0xB0, 0xF6, 0xF3, 0x06, 0x1C, 0xE2, 0xB1, 0x9D, 0x87, 0x30, 0x1E, 0x41, 0xD2, 0x30, 0xF4, 0x1B, 0x65, 0x1A, 0x37, 0x55, 0xF9, 0xCF, 0x15, 0xE5, 0xF6, 0x9A, 0xC6, 0x1A, 0xDF, 0xC8, 0x69, 0x1A, 0xF2, 0x60, 0x9E, 0xDE, 0xD7, 0x9D, 0x7C, 0x91, 0xE5, 0xBF, 0x8E, 0x47, 0x66, 0xBA, 0xCF, 0x95, 0x07, 0x2C, 0xFC, 0xC5, 0xFF, 0x10, 0xFA, 0xD2, 0xEB, 0xC5, 0x1F, 0xDE, 0x92, 0x7C, 0x18, 0x27, 0x7D, 0x6E, 0xDE, 0xFE, 0xF6, 0x36, 0x0D, 0x73, 0xFC, 0x97, 0xD7, 0xE0, 0x92, 0xCC, 0xCD, 0xBB, 0xA2, 0xBF, 0x7D, 0xD0, 0x73, 0x76, 0x68, 0x6B, 0xE1, 0xA1, 0x2A, 0xDF, 0xFF, 0xE9, 0xED, 0x3F, 0x5E, 0x15, 0xF1, 0x62, 0x7B, 0xD6, 0xD5, 0xAB, 0x06, 0x0E, 0xAE, 0x26, 0x5E, 0xDF, 0x1C, 0x59, 0xE2, 0x8F, 0x37, 0x3D, 0xEE, 0xE7, 0x78, 0x9C, 0xBE, 0xFF, 0xD3, 0x5F, 0x5E, 0xD1, 0x3E, 0x46, 0xF9, 0xA1, 0x6D, 0x86, 0xF8, 0x30, 0x66, 0xE3, 0x74, 0x88, 0x0A, 0x33, 0xBF, 0x49, 0xE3, 0x83, 0xEB, 0xC7, 0x24, 0x3E, 0x09, 0x7D, 0xFD, 0xE5, 0xC9, 0xDB, 0xF7, 0x9F, 0xB8, 0xDE, 0x79, 0x1E, 0x2F, 0x9E, 0xB7, 0xBF, 0xFD, 0xED, 0xED, 0xF4, 0xF6, 0xC7, 0x3F, 0xFE, 0x28, 0xF0, 0x25, 0x69, 0x1E, 0x5F, 0xC1, 0x08, 0x04, 0x7D, 0xC6, 0xFE, 0xF6, 0x56, 0x6F, 0x6A, 0x50, 0x1C, 0xD2, 0x5F, 0xB9, 0xFD, 0xA1, 0x7B, 0x5D, 0xDB, 0xFB, 0xFD, 0x94, 0xE5, 0xE3, 0x21, 0x6C, 0xEC, 0xDA, 0x66, 0x8C, 0x8D, 0xA3, 0x0E, 0x3E, 0x64, 0xEE, 0xC3, 0xDF, 0x61, 0x9C, 0xE6, 0x3A, 0x6E, 0xA6, 0x1F, 0x8E, 0xEA, 0x67, 0xAA, 0xF8, 0xF5, 0x48, 0x6D, 0xB7, 0xE8, 0xFB, 0x1F, 0x0F, 0xEB, 0xFE, 0xD3, 0x0F, 0x79, 0xD3, 0xC4, 0x03, 0x6F, 0xC8, 0xD2, 0x21, 0xF6, 0x5D, 0xFC, 0x0F, 0x1F, 0x69, 0x7F, 0x79, 0x69, 0xFA, 0x2F, 0x0A, 0xF8, 0x78, 0x64, 0xD6, 0xD7, 0xF8, 0x3F, 0x90, 0xBE, 0xCD, 0xFE, 0xE3, 0x31, 0x58, 0x5F, 0x13, 0xF0, 0x89, 0xF8, 0x06, 0xBC, 0xFD, 0xDB, 0x9B, 0x48, 0xFD, 0xDB, 0xB7, 0x45, 0xE5, 0x5F, 0x17, 0x92, 0x77, 0xDF, 0x66, 0xFB, 0xB4, 0x2B, 0xFA, 0x6B, 0xBC, 0x1F, 0x69, 0xDF, 0x16, 0xF0, 0xBE, 0xFF, 0xF9, 0x6B, 0xDC, 0x2F, 0xC2, 0xB7, 0x59, 0x3F, 0x6E, 0x72, 0xFE, 0x1A, 0xF3, 0x07, 0xD2, 0xAF, 0xA4, 0xFC, 0xE3, 0x4A, 0xBB, 0xAF, 0x26, 0xFF, 0x89, 0xFA, 0x6D, 0x21, 0xAF, 0x95, 0x6E, 0x5F, 0x63, 0x3F, 0xC2, 0x7F, 0x85, 0xF1, 0x17, 0xBA, 0x4D, 0xF5, 0x6B, 0x5D, 0xE6, 0x7D, 0xA9, 0xDA, 0x57, 0xCB, 0x7C, 0x10, 0xBE, 0xCD, 0xFA, 0xBE, 0xC6, 0xEC, 0x6B, 0xAC, 0x2F, 0xC2, 0xB7, 0x59, 0x3F, 0x3F, 0x10, 0xED, 0x6B, 0x12, 0x3E, 0xA3, 0xFF, 0xC6, 0xFE, 0xF6, 0xD3, 0xF9, 0x67, 0x5F, 0xED, 0x77, 0x3F, 0x92, 0x7F, 0x45, 0xCC, 0xE7, 0x87, 0x9B, 0x7D, 0x55, 0xD0, 0x67, 0x11, 0xDE, 0x73, 0xF6, 0xF6, 0xC7, 0x28, 0x4E, 0xFF, 0x72, 0xFD, 0x95, 0xEC, 0x7D, 0xB6, 0xC7, 0xFD, 0xAB, 0xC5, 0xFD, 0x91, 0xFC, 0x6B, 0xAD, 0xFC, 0xBE, 0xC4, 0xF2, 0xEB, 0x0D, 0xFD, 0x22, 0x7D, 0x9B, 0xFD, 0xE7, 0x5F, 0xE5, 0xBE, 0x3A, 0xCA, 0x7C, 0x1E, 0xE3, 0xDB, 0xC2, 0xBE, 0xF8, 0xFA, 0xF4, 0x35, 0x69, 0x3F, 0x8F, 0xF2, 0xFF, 0x50, 0x5D, 0x9F, 0x7D, 0xCA, 0xFB, 0x05, 0xB9, 0x1F, 0xC9, 0xDF, 0x16, 0xF3, 0xF9, 0xF7, 0xBA, 0xAF, 0xC9, 0xF9, 0x8C, 0xFE, 0x2E, 0xE8, 0x65, 0x09, 0x3E, 0x59, 0xA6, 0xF7, 0x11, 0xFE, 0x70, 0xAA, 0x3E, 0xB3, 0x54, 0x89, 0x5F, 0x8D, 0x1F, 0x2A, 0xE5, 0x1B, 0xEA, 0xF4, 0x33, 0xE7, 0xF2, 0x4F, 0x3F, 0xBC, 0xBB, 0x85, 0x3F, 0xE9, 0xD4, 0x3B, 0xF5, 0x57, 0x44, 0xFC, 0xE4, 0x54, 0xFE, 0x5F, 0xEC, 0x47, 0xE0, 0x07, 0xE6, 0x7F, 0x7E, 0xB2, 0x26, 0xEF, 0x0F, 0xFF, 0xFC, 0xB9, 0xE5, 0xEB, 0xE2, 0xE6, 0xFB, 0xEF, 0x38, 0xC6, 0xF8, 0xEE, 0xCF, 0x6F, 0xDF, 0x15, 0xE3, 0xA1, 0x11, 0x7F, 0x7E, 0x37, 0xB2, 0x3F, 0xB7, 0x8F, 0x63, 0xDC, 0x44, 0xEF, 0x26, 0xF3, 0x9F, 0xEF, 0xC6, 0xF7, 0x4B, 0x9B, 0x7B, 0x04, 0x1E, 0xB5, 0xF2, 0x7E, 0x1C, 0xE0, 0x91, 0x87, 0xEF, 0x7F, 0x4E, 0xFE, 0xF3, 0x1B, 0x06, 0x1D, 0x36, 0xF0, 0x9D, 0xF1, 0xB0, 0xFF, 0xEF, 0x96, 0xFD, 0xE3, 0xE5, 0xCB, 0x1F, 0xFD, 0xB0, 0xBF, 0xBE, 0xDF, 0x62, 0x7F, 0x3C, 0xFC, 0x1F, 0x4B, 0x85, 0x9F, 0x93, 0x22, 0x7F, 0x00, 0x00 +}; diff --git a/src/indextprocessor.py b/src/indextprocessor.py new file mode 100644 index 0000000..dc2029a --- /dev/null +++ b/src/indextprocessor.py @@ -0,0 +1,25 @@ +import gzip +import os + +if __name__ == '__main__': + with open('src/index.html', 'rb') as orig_file: + with gzip.open("src/index.h.gz", 'wb') as zipped_file: + zipped_file.writelines(orig_file) + + file_size = os.path.getsize('src/index.h.gz') + + with open('src/index.h.gz', 'rb') as file_t: + block = file_t.read() + st = "" + for ch in block: + st += '0x%02X' % ch + ", " + st = st[:-2] + + with open('src/index_bytearray.h', 'wt') as text_file: + text_file.write('#define index_gz_len ' + str(file_size) + '\nconst uint8_t index_gz[] PROGMEM = {\n') + + with open('src/index_bytearray.h', 'at') as text_file: + text_file.write(st) + + with open('src/index_bytearray.h', 'at') as text_file: + text_file.write('\n};\n') \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b48ceb9..1ae026a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,1144 +1,1552 @@ -// WiFi enabled GPS NTP server - Cristiano Monteiro - 06.May.2021 -// Based on the work of: -// Bruce E. Hall, W8BH - http://w8bh.net -// and -// https://forum.arduino.cc/u/ziggy2012/summary -// -// Contributions from: -// https://github.com/mmarkin -// https://github.com/sjthespian - -#include -#include - -// State data -#include - -// For time on the web page -#include // For formatting time - -// Needed for UDP functionality -#include -// Time Server Port -#define NTP_PORT 123 -static const int NTP_PACKET_SIZE = 48; -// buffers for receiving and sending data -byte packetBuffer[NTP_PACKET_SIZE]; -// An Ethernet UDP instance -WiFiUDP Udp; - -// Syslog support -#include - -/* Create a WiFi access point and provide a web server on it. */ -#include -#include -#include -#include -#include // We will use clock's eeprom to store config - -// function prototypes -void processWifi(); // Need to declare this for handleUpdate() -void UpdateDisplay(); -void processKeyHold(); -void processKeyPress(); - -// GLOBAL DEFINES -#define HOSTNAME "ESP-NTP-Server" // Hostname used for syslog and DHCP -#define WIFIRETRIES 15 // Max number of wifi retry attempts -#define APSSID "GPSTimeServer" // Default AP SSID -#define APPSK "thereisnospoon" // Default password -#define PPS_PIN D6 // Pin on which 1PPS line is attached -#define SYNC_INTERVAL 10 // time, in seconds, between GPS sync attempts -#define SYNC_TIMEOUT 30 // time(sec) without GPS input before error -// #define RTC_UPDATE_INTERVAL SECS_PER_DAY // time(sec) between RTC SetTime events -#define RTC_UPDATE_INTERVAL 30 // time(sec) between RTC SetTime events -#define PPS_BLINK_INTERVAL 50 // Set time pps led should be on for blink effect -// #define SYSLOG_SERVER "x.x.x.x" // syslog server name or IP -#define SYSLOG_PORT 514 // syslog port - -#define LOCK_LED D3 -#define PPS_LED 10 -#define WIFI_LED D5 -#define WIFI_BUTTON D4 -#define BTN_HOLD_MS 2000 // Number of milliseconds to determine button being held -#define BTN_NONE 0 // No button press -#define BTN_PRESS 1 // Button pressed for < BTN_HOLD_MS -#define BTN_HOLD 2 // Button held for at least BTN_HOLD_MS - -// INCLUDES -#include -#include // Time functions https://github.com/PaulStoffregen/Time -#include // GPS parsing https://github.com/mikalhart/TinyGPSPlus -#include // OLED and DS3231 necessary -#include // RTC functions - -RtcDS3231 Rtc(Wire); -EepromAt24c32 RtcEeprom(Wire); - -// U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE); // OLED display library parameters -U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE); // OLED display library parameters - -TinyGPSPlus gps; -SoftwareSerial ss(D7, D8); // Serial GPS handler -time_t displayTime = 0; // time that is currently displayed -time_t syncTime = 0; // time of last GPS or RTC synchronization -time_t lastSetRTC = 0; // time that RTC was last set -volatile int pps = 0; // GPS one-pulse-per-second flag -time_t dstStart = 0; // start of DST in unix time -time_t dstEnd = 0; // end of DST in unix time -bool gpsLocked = false; // indicates recent sync with GPS -int currentYear = 0; // used for DST -int displaynum = 0; // Display pane currently displayed -#define NUMDISPLAYPANES 2 // Number of display panes available - -long int pps_blink_time = 0; - -/* Set these to your desired credentials. */ -const char *ssid = APSSID; -const char *password = APPSK; -String wifissid; -String wifipassword; -String syslogserver; -uint8_t statusWifi = 1; - -ESP8266WebServer server(80); - -// rdate server -WiFiServer RFC868server(37); - -// A UDP instance to let us send and receive packets over UDP -WiFiUDP udpClient; -// Create syslogt instance with LOG_DAEMON -// Create a new empty syslog instance -Syslog syslog(udpClient, SYSLOG_PROTO_IETF); -/* - * ISR Debounce - */ - -// use 150ms debounce time -#define DEBOUNCE_TICKS 100 - -word keytick_down = 0; // record time of keypress -word keytick_up = 0; -int lastState = HIGH; // record last button state to support debouncing - -// #define DEBUG // Comment this in order to remove debug code from release version -// #define DEBUG_GPS // Uncomment this to receive GPS messages in debug output - -#ifdef DEBUG -#define DEBUG_PRINT(x) Serial.print(x) -#define DEBUG_PRINTDEC(x) Serial.print(x, DEC) -#define DEBUG_PRINTLN(x) Serial.println(x) -#else -#define DEBUG_PRINT(x) -#define DEBUG_PRINTDEC(x) -#define DEBUG_PRINTLN(x) -#endif - -// Button ISR debouncing routine - -// returns true if key pressed - -void KeyCheck() -{ - // Button pressed and released - int button_type = 0; - if (keytick_up > 0 and keytick_down > 0 and ((keytick_down - keytick_up) >= DEBOUNCE_TICKS)) - { - if ((keytick_down - keytick_up) > BTN_HOLD_MS) - { - button_type = BTN_HOLD; - } - else - { - button_type = BTN_PRESS; - } - - // return button_type; - switch (button_type) - { - case BTN_HOLD: // Malabarism to cover mechanical switch debouncing - processKeyHold(); - break; - case BTN_PRESS: - processKeyPress(); - break; - } - } - // return BTN_NONE; -} - -// littleFS routines - -String readData(const char *filename) -{ - DEBUG_PRINT("Reading data from "); - DEBUG_PRINT(filename); - File file = LittleFS.open(filename, "r"); - - String data = ""; - if (!file) - { - DEBUG_PRINTLN("ERROR: File open failed!"); - } - else - { - - if (file.available()) - { - data = file.readString(); - } - DEBUG_PRINT(" : "); - DEBUG_PRINTLN(data); - - file.close(); - } - - return data; -} - -void writeData(const char *filename, String data) -{ - DEBUG_PRINT("Writing data to "); - DEBUG_PRINT(filename); - File file = LittleFS.open(filename, "w"); - - if (!file) - { - DEBUG_PRINTLN("ERROR: File open failed!"); - } - else - { - file.println(data); - DEBUG_PRINT(" : "); - DEBUG_PRINTLN(data); - } - - file.close(); -} - -// WiFi and Web Routines - -void handleUpdate() -{ - wifissid = server.arg("wifi_ssid"); - wifipassword = server.arg("wifi_psk"); - syslogserver = server.arg("syslog_server"); - DEBUG_PRINTLN("Settings Updated!"); - DEBUG_PRINTLN(wifissid); - // DEBUG_PRINTLN(wifipassword); - // Save SSID and password in littlefs - writeData("/wifissid", wifissid); - if (wifipassword != "") - writeData("/wifipsk", wifipassword); - writeData("/syslogserver", syslogserver); - - processWifi(); - - String content = "Return to main page"; - server.send(200, "text/html", content); -} - -void handleRoot() -{ - char webpage[2048]; - char timestr[32]; - - // Build string for web UI - time_t t = now(); // get current time - tm *ptm = gmtime(&t); - strftime(timestr, 32, "%Y-%m-%d %H:%M:%S UTC", ptm); - - int sats = (gps.satellites.value() != 255) ? gps.satellites.value() : 0; - String resol = gpsLocked ? String(gps.hdop.value()) : ""; - - // latitude & longitude - float lat = 0.0; - float lng = 0.0; - if (gpsLocked) - { - lat = gps.location.lat(); - lng = gps.location.lng(); - } - - char form[512] = {0}; - // if (WiFi.getMode() == WIFI_AP) { - sprintf(form, "

Settings

Syslog server:
SSID:
Password:
", syslogserver.c_str(), wifissid.c_str()); - // } - - sprintf(webpage, - "NTP Server

%s

Satellites: %d Resolution: %s

Location

Latitude: %7.4f, Longitude: %7.4f
%s", - timestr, - sats, - resol.c_str(), - (float)lat, - (float)lng, - form); - server.send(200, "text/html", webpage); -} - -void startHttpServer() -{ - server.on("/", handleRoot); - server.on("/updatewifi", handleUpdate); - server.begin(); - DEBUG_PRINTLN(F("HTTP server started")); - syslog.log(LOG_INFO, "HTTP server started"); -} - -void enableWifiAP() -{ - // WiFi Initialization as an AP - /* You can remove the password parameter if you want the AP to be open. */ - WiFi.mode(WIFI_AP); - // WiFi.softAP(ssid, psk, channel, hidden, max_connection) - // Setting maximum of 8 clients, 1 is default channel already, 0 is false for hidden SSID - The maximum allowed by ES8266 is 8 - Thanks to Mitch Markin for that - WiFi.softAP(ssid, password, 1, 0, 8); - -#ifdef DEBUG - IPAddress myIP = WiFi.softAPIP(); - DEBUG_PRINT(F("AP IP address: ")); - DEBUG_PRINTLN(myIP); -#endif - startHttpServer(); -} - -void enableWifi() -{ - // Get SSID and password from littleFS - wifissid = readData("/wifissid"); - wifipassword = readData("/wifipsk"); // Password follows - - wifissid.trim(); - wifipassword.trim(); - // Connect to WiFi - WiFi.setHostname(HOSTNAME); - WiFi.mode(WIFI_STA); - DEBUG_PRINTLN("Connecting to WiFI"); - DEBUG_PRINTLN(wifissid); - DEBUG_PRINTLN(wifipassword); - WiFi.begin(wifissid, wifipassword); - int retries = 0; - while ((WiFi.status() != WL_CONNECTED) && (retries < WIFIRETRIES)) - { - retries++; - delay(500); - DEBUG_PRINT("."); - } - if (retries >= WIFIRETRIES) - { - enableWifiAP(); - } - if (WiFi.status() == WL_CONNECTED) - { -#ifdef DEBUG - IPAddress myIP = WiFi.localIP(); - if (myIP[0] == 0) - myIP = WiFi.softAPIP(); - DEBUG_PRINTLN(F("WiFi connected!")); - DEBUG_PRINT("IP address: "); - DEBUG_PRINTLN(myIP); - syslog.logf(LOG_INFO, "WiFi connected as %s", myIP.toString().c_str()); -#endif - startHttpServer(); - } -} - -void disableWifi() -{ - server.stop(); - DEBUG_PRINTLN(F("HTTP server stopped")); - syslog.log(LOG_WARNING, "WiFi disabled!"); - if (WiFi.getMode() == WIFI_AP) - { - WiFi.softAPdisconnect(true); - WiFi.enableAP(false); - } - WiFi.mode(WIFI_OFF); - WiFi.forceSleepBegin(); - DEBUG_PRINTLN(F("WiFi disabled")); -} - -void processWifi() -{ - // Toggle WiFi on/off and corresponding LED - DEBUG_PRINT(F("Status Wifi: ")); - DEBUG_PRINTLN(statusWifi); - - if (statusWifi) - { - enableWifi(); - digitalWrite(WIFI_LED, HIGH); - } - else - { - disableWifi(); - digitalWrite(WIFI_LED, LOW); - } -} - -// -------------------------------------------------------------------------------------------------- -// SERIAL MONITOR ROUTINES -// These routines print the date/time information to the serial monitor -// Serial monitor must be initialized in setup() before calling - -void PrintDigit(int d) -{ - if (d < 10) - DEBUG_PRINT('0'); - DEBUG_PRINT(d); -} - -void PrintTime(time_t t) -// display time and date to serial monitor -{ - PrintDigit(month(t)); - DEBUG_PRINT("-"); - PrintDigit(day(t)); - DEBUG_PRINT("-"); - PrintDigit(year(t)); - DEBUG_PRINT(" "); - PrintDigit(hour(t)); - DEBUG_PRINT(":"); - PrintDigit(minute(t)); - DEBUG_PRINT(":"); - PrintDigit(second(t)); - DEBUG_PRINTLN(" UTC"); -} - -// -------------------------------------------------------------------------------------------------- -// RTC SUPPORT -// These routines add the ability to get and/or set the time from an attached real-time-clock module -// such as the DS1307 or the DS3231. The module should be connected to the I2C pins (SDA/SCL). - -void PrintRTCstatus() -// send current RTC information to serial monitor -{ - RtcDateTime Now = Rtc.GetDateTime(); - time_t t = Now.Epoch32Time(); - if (t) - { - DEBUG_PRINT("PrintRTCstatus: "); - DEBUG_PRINTLN("Called PrintTime from PrintRTCstatus"); -#ifdef DEBUG - PrintTime(t); -#endif - } - else - { - DEBUG_PRINTLN("ERROR: cannot read the RTC."); - syslog.log(LOG_ERR, "ERROR: cannot read the RTC."); - } -} - -// Update RTC from current system time -void SetRTC(time_t t) -{ - RtcDateTime timeToSet; - - timeToSet.InitWithEpoch32Time(t); - - Rtc.SetDateTime(timeToSet); - if (Rtc.LastError() == 0) - { - DEBUG_PRINT("SetRTC: "); - DEBUG_PRINTLN("Called PrintTime from SetRTC"); -#ifdef DEBUG - PrintTime(t); -#endif - } - else - { - DEBUG_PRINT("ERROR: cannot set RTC time"); - syslog.log(LOG_ERR, "ERROR: cannot set RTC time"); - } -} - -void ManuallySetRTC() -// Use this routine to manually set the RTC to a specific UTC time. -// Since time is automatically set from GPS, this routine is mainly for -// debugging purposes. Change numeric constants to the time desired. -{ - // tmElements_t tm; - // tm.Year = 2017 - 1970; // Year in unix years - // tm.Month = 5; - // tm.Day = 31; - // tm.Hour = 5; - // tm.Minute = 59; - // tm.Second = 30; - // SetRTC(makeTime(tm)); // set RTC to desired time -} - -void UpdateRTC() -// keep the RTC time updated by setting it every (RTC_UPDATE_INTERVAL) seconds -// should only be called when system time is known to be good, such as in a GPS sync event -{ - time_t t = now(); // get current time - if ((t - lastSetRTC) >= RTC_UPDATE_INTERVAL) // is it time to update RTC internal clock? - { - DEBUG_PRINT("Called SetRTC from UpdateRTC with "); - DEBUG_PRINTLN(t); - SetRTC(t); // set RTC with current time - lastSetRTC = t; // remember time of this event - } -} - -// -------------------------------------------------------------------------------------------------- -// LCD SPECIFIC ROUTINES -// These routines are used to display time and/or date information on the LCD display -// Assumes the presence of a global object "lcd" of the type "LiquidCrystal" like this: -// LiquidCrystal lcd(6,9,10,11,12,13); -// where the six numbers represent the digital pin numbers for RS,Enable,D4,D5,D6,and D7 LCD pins - -void ShowDate(time_t t) -{ - String data = ""; - - int y = year(t); - if (y < 10) - data = data + "0"; - data = data + String(y) + "-"; - - int m = month(t); - if (m < 10) - data = data + "0"; - data = data + String(m) + "-"; - - int d = day(t); - if (d < 10) - data = data + "0"; - data = data + String(d); - - u8g2.setFont(u8g2_font_open_iconic_all_2x_t); - u8g2.drawGlyph(0, 43, 107); - - u8g2.setFont(u8g2_font_logisoso16_tf); // choose a suitable font - u8g2.drawStr(18, 43, data.c_str()); - - DEBUG_PRINTLN("UpdateDisplay"); -} - -void ShowTime(time_t t) -{ - String hora = ""; - int h = hour(t); - if (h < 10) - hora = hora + "0"; - hora = hora + String(h) + ":"; - - int m = minute(t); - if (m < 10) - hora = hora + "0"; - hora = hora + String(m) + ":"; - - int s = second(t); - if (s < 10) - hora = hora + "0"; - hora = hora + String(s) + " UTC"; - - u8g2.setFont(u8g2_font_open_iconic_all_2x_t); - u8g2.drawGlyph(0, 64, 123); - - u8g2.setFont(u8g2_font_logisoso16_tf); // choose a suitable font - u8g2.drawStr(16, 64, hora.c_str()); -} - -void ShowDateTime(time_t t) -{ - ShowDate(t); - - ShowTime(t); -} - -void ShowSyncFlag() -{ - String sats = ""; - if (gps.satellites.value() != 255) - sats = String(gps.satellites.value()); - else - sats = "0"; - - if (gpsLocked) - digitalWrite(LOCK_LED, HIGH); - // else - // digitalWrite(LOCK_LED, LOW); - - String resol = ""; - if (gpsLocked) - resol = String(gps.hdop.value()); - else - resol = "0"; - - u8g2.setFont(u8g2_font_open_iconic_all_2x_t); - u8g2.drawGlyph(0, 16, 259); - u8g2.drawGlyph(64, 16, 263); - - u8g2.setFont(u8g2_font_logisoso16_tf); // choose a suitable font - u8g2.drawStr(18, 16, sats.c_str()); - u8g2.drawStr(82, 16, resol.c_str()); -} - -void ShowWifiNetwork() -{ - String wifinet = ""; - - if (WiFi.getMode() == WIFI_STA) - wifinet = wifissid; - else - wifinet = APSSID; - - u8g2.setFont(u8g2_font_open_iconic_all_2x_t); - u8g2.drawGlyph(0, 43, 248); - - int wrap = 38; - int ypos1 = 28; - int ypos2 = 43; - // Play games with the font and spacing based on the length of the SSID - if (wifinet.length() > 30) - { - u8g2.setFont(u8g2_font_6x12_tf); // Small font for long SSID - wrap = 18; - } - else if (wifinet.length() > 20) - { - u8g2.setFont(u8g2_font_7x13_tf); // Not quite as small - wrap = 15; - } - else if (wifinet.length() > 11) - { - u8g2.setFont(u8g2_font_7x13_tf); // Not quite as small on one line - ypos1 = 43; - } - else - { - u8g2.setFont(u8g2_font_10x20_tf); // Readable on one line - ypos1 = 43; - } - u8g2.drawStr(16, ypos1, wifinet.substring(0, wrap).c_str()); - if (wifinet.length() > 20) // 2nd line needed if > 20 - u8g2.drawStr(16, ypos2, wifinet.substring(wrap).c_str()); -} - -void ShowIPAddress() -{ - IPAddress myIP = WiFi.localIP(); - if (myIP[0] == 0) - myIP = WiFi.softAPIP(); - - u8g2.setFont(u8g2_font_logisoso16_tr); // choose a suitable font - u8g2.drawStr(0, 64, myIP.toString().c_str()); -} - -void InitLCD() -{ - u8g2.begin(); // Initialize OLED library -} - -// -------------------------------------------------------------------------------------------------- -// TIME SYNCHONIZATION ROUTINES -// These routines will synchonize time with GPS and/or RTC as necessary -// Sync with GPS occur when the 1pps interrupt signal from the GPS goes high. -// GPS synchonization events are attempted every (SYNC_INTERVAL) seconds. -// If a valid GPS signal is not received within (SYNC_TIMEOUT) seconds, the clock with synchonized -// with RTC instead. The RTC time is updated with GPS data once every 24 hours. - -void SyncWithGPS() -{ - int y; - // byte h, m, s, mon, d, hundredths; - byte h, m, s, mon, d; - unsigned long age; - y = gps.date.year(); - mon = gps.date.month(); - d = gps.date.day(); - h = gps.time.hour(); - m = gps.time.minute(); - s = gps.time.second(); - age = gps.location.age(); - // gps.crack_datetime(&y, &mon, &d, &h, &m, &s, NULL, &age); // get time from GPS - // cheise @ Github spotted the uneccessary and wrong '> 3000' condition. Fixed - 20230206 - // if (age < 1000 or age > 3000) - if (age < 1000) // dont use data older than 1 second - { - setTime(h, m, s, d, mon, y); // copy GPS time to system time - DEBUG_PRINT("Time from GPS: "); - DEBUG_PRINT(h); - DEBUG_PRINT(":"); - DEBUG_PRINT(m); - DEBUG_PRINT(":"); - DEBUG_PRINTLN(s); - adjustTime(1); // 1pps signal = start of next second - syncTime = now(); // remember time of this sync - if (!gpsLocked) - { - syslog.logf(LOG_INFO, "GPS sychronized - %d satellites", gps.satellites.value()); - } - gpsLocked = true; // set flag that time is reflects GPS time - UpdateRTC(); // update internal RTC clock periodically - DEBUG_PRINTLN("GPS synchronized"); // send message to serial monitor - } - else - { - DEBUG_PRINT("Age: "); - DEBUG_PRINTLN(age); - } -} - -void SyncWithRTC() -{ - RtcDateTime time = Rtc.GetDateTime(); - long int a = time.Epoch32Time(); - setTime(a); // set system time from RTC - DEBUG_PRINT("SyncFromRTC: "); - DEBUG_PRINTLN(a); - syncTime = now(); // and remember time of this sync event - DEBUG_PRINTLN("Synchronized from RTC"); // send message to serial monitor -} - -void SyncCheck() -// Manage synchonization of clock to GPS module -// First, check to see if it is time to synchonize -// Do time synchonization on the 1pps signal -// This call must be made frequently (keep in main loop) -{ - unsigned long timeSinceSync = now() - syncTime; // how long has it been since last sync? - if (pps && (timeSinceSync >= SYNC_INTERVAL)) - { // is it time to sync with GPS yet? - DEBUG_PRINTLN("Called SyncWithGPS from SyncCheck"); - SyncWithGPS(); // yes, so attempt it. - } - pps = 0; // reset 1-pulse-per-second flag, regardless - if (timeSinceSync >= SYNC_TIMEOUT) // GPS sync has failed - { - if (gpsLocked) - { - syslog.log(LOG_INFO, "GPS sych lost!"); - } - gpsLocked = false; // flag that clock is no longer in GPS sync - DEBUG_PRINTLN("Called SyncWithRTC from SyncCheck"); - SyncWithRTC(); // sync with RTC instead - } -} - -// -------------------------------------------------------------------------------------------------- -// MAIN PROGRAM - -void IRAM_ATTR isr() // INTERRUPT SERVICE REQUEST -{ - pps = 1; // Flag the 1pps input signal - digitalWrite(PPS_LED, HIGH); // Ligth up led pps monitor - pps_blink_time = millis(); // Capture time in order to turn led off so we can get the blink effect ever x milliseconds - On loop - DEBUG_PRINTLN("pps"); -} - -// Handle button pressed interrupt -void IRAM_ATTR btw() // INTERRUPT SERVICE REQUEST -{ - int currentState = digitalRead(WIFI_BUTTON); - if (currentState != lastState) - { - if (lastState == HIGH) - { - keytick_up = millis(); - } - else - { - keytick_down = millis(); - KeyCheck(); - } - lastState = currentState; - } - DEBUG_PRINTLN(F("BUTTON PRESSED!")); -} - -void processKeyHold() -{ - if (statusWifi) - statusWifi = 0; - else - statusWifi = 1; - - processWifi(); - DEBUG_PRINTLN(F("BUTTON HOLD PROCESSED!")); -} - -void processKeyPress() -{ - DEBUG_PRINTLN(F("BUTTON CLICK PROCESSED!")); - displaynum++; - if (displaynum >= NUMDISPLAYPANES) - { - displaynum = 0; - } - UpdateDisplay(); -} - -void setup() -{ - pinMode(LOCK_LED, OUTPUT); - pinMode(PPS_LED, OUTPUT); - pinMode(WIFI_LED, OUTPUT); - pinMode(WIFI_BUTTON, INPUT_PULLUP); - - digitalWrite(LOCK_LED, LOW); - digitalWrite(PPS_LED, LOW); - digitalWrite(WIFI_LED, LOW); - // if you are using ESP-01 then uncomment the line below to reset the pins to - // the available pins for SDA, SCL - Wire.begin(D2, D1); // due to limited pins, use pin 0 and 2 for SDA, SCL - Rtc.Begin(); - RtcEeprom.Begin(); - - LittleFS.begin(); // Init storage for WiFi SSID/PSK - - InitLCD(); // initialize LCD display - - ss.begin(9600); // set GPS baud rate to 9600 bps -#ifdef DEBUG - Serial.begin(9600); // set serial monitor rate to 9600 bps -#endif - - // Serial.begin(9600); - delay(2000); - - syslogserver = readData("/syslogserver"); // Password follows - syslogserver.trim(); - - IPAddress ip; - ip.fromString(syslogserver); - // Syslog syslog(udpClient, syslogserver, SYSLOG_PORT, HOSTNAME, "esp-ntp", LOG_DAEMON); - syslog.server(ip, SYSLOG_PORT); - syslog.deviceHostname(HOSTNAME); - syslog.appName("esp-ntp"); - syslog.defaultPriority(LOG_DAEMON); - - DEBUG_PRINTLN("Iniciado"); - - // Initialize RTC - while (!Rtc.GetIsRunning()) - { - Rtc.SetIsRunning(true); - DEBUG_PRINTLN(F("RTC had to be force started")); - syslog.log(LOG_WARNING, "RTC had to be force started"); - } - - DEBUG_PRINTLN(F("RTC started")); - - // never assume the Rtc was last configured by you, so - // just clear them to your needed state - Rtc.Enable32kHzPin(false); - Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone); - -#ifdef DEBUG - PrintRTCstatus(); // show RTC diagnostics -#endif - SyncWithRTC(); // start clock with RTC data - attachInterrupt(PPS_PIN, isr, RISING); // enable GPS 1pps interrupt input - attachInterrupt(WIFI_BUTTON, btw, CHANGE); - - processWifi(); - - // Startup UDP - Udp.begin(NTP_PORT); - RFC868server.begin(); -} - -void FeedGpsParser() -// feed currently available data from GPS module into tinyGPS parser -{ - while (ss.available()) // look for data from GPS module - { - char c = ss.read(); // read in all available chars - gps.encode(c); // and feed chars to GPS parser - // Serial.write(c); // Uncomment for some extra debug info if in doubt about GPS feed -#ifdef DEBUG_GPS - DEBUG_PRINT(c); -#endif - // Will toggle LOCK_LED at each pass if not locked, so user can see the GPS is actually doing something - if (!gpsLocked) - digitalWrite(LOCK_LED, !digitalRead(LOCK_LED)); - // Serial.print(c); - } -} - -void UpdateDisplay() -// Call this from the main loop -// Updates display if time has changed -{ - time_t t = now(); // get current time - if (t != displayTime) // has time changed? - { - u8g2.clearBuffer(); // Clear buffer contents - switch (displaynum) - { - case 0: - ShowDateTime(t); // Display the new UTC time - ShowSyncFlag(); // show if display is in GPS sync - break; - case 1: - ShowWifiNetwork(); - ShowIPAddress(); - break; - } - u8g2.sendBuffer(); // Send new information to display - - displayTime = t; // save current display value - DEBUG_PRINTLN("Called PrintTime from UpdateDisplay"); -#ifdef DEBUG - PrintTime(t); // copy time to serial monitor -#endif - } -} - -//////////////////////////////////////// - -const uint8_t daysInMonth[] PROGMEM = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // const or compiler complains - -const unsigned long seventyYears = 2208988800UL; // to convert unix time to epoch - -// Replaced with better, less verbose, more elegant timestamp = t + seventyYears calculation, suggested by cheise @ Github - 20230206 -// NTP since 1900/01/01 -// static unsigned long int numberOfSecondsSince1900Epoch(uint16_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t mm, uint8_t s) -// { -// if (y >= 1970) -// y -= 1970; -// uint16_t days = d - 1; -// for (uint8_t i = 1; i < m; ++i) -// days += pgm_read_byte(daysInMonth + i - 1); -// if (m > 2 && y % 4 == 0) -// ++days; -// days += 365 * y + (y + 3) / 4 - 1; -// return days * 24L * 3600L + h * 3600L + mm * 60L + s + seventyYears; -// } - -//////////////////////////////////////// - -// Process rdate request -// Return the time as the number of seconds since 1/1/1900 -void processRFC868() -{ - uint32_t timestamp; - WiFiClient client = RFC868server.accept(); - client.setNoDelay(true); - - if (client.connected()) - { - syslog.logf(LOG_INFO, "RDATE request from %s", client.remoteIP().toString().c_str()); - // Serial.println(client.remoteIP().toString().c_str()); - - // Send Data to connected client - time_t t = now(); // get current time - - timestamp = t + seventyYears; - - uint8_t bytes[4]; - - // Populate big endian byte array - bytes[0] = (timestamp >> 24) & 0xFF; - bytes[1] = (timestamp >> 16) & 0xFF; - bytes[2] = (timestamp >> 8) & 0xFF; - bytes[3] = (timestamp >> 0) & 0xFF; - - client.write((const uint8_t *)bytes, sizeof(timestamp)); - // Serial.println(timestamp); - - // Disconnect client - client.stop(); - } -} - -void processNTP() -{ - - // if there's data available, read a packet - int packetSize = Udp.parsePacket(); - if (packetSize) - { - Udp.read(packetBuffer, NTP_PACKET_SIZE); - IPAddress Remote = Udp.remoteIP(); - int PortNum = Udp.remotePort(); - - syslog.logf(LOG_INFO, "NTP request from %s", Remote.toString().c_str()); - -#ifdef DEBUG - Serial.println(); - Serial.print("Received UDP packet size "); - Serial.println(packetSize); - Serial.print("From "); - - for (int i = 0; i < 4; i++) - { - Serial.print(Remote[i], DEC); - if (i < 3) - { - Serial.print("."); - } - } - Serial.print(", port "); - Serial.print(PortNum); - - byte LIVNMODE = packetBuffer[0]; - Serial.print(" LI, Vers, Mode :"); - Serial.print(LIVNMODE, HEX); - - byte STRATUM = packetBuffer[1]; - Serial.print(" Stratum :"); - Serial.print(STRATUM, HEX); - - byte POLLING = packetBuffer[2]; - Serial.print(" Polling :"); - Serial.print(POLLING, HEX); - - byte PRECISION = packetBuffer[3]; - Serial.print(" Precision :"); - Serial.println(PRECISION, HEX); - - for (int z = 0; z < NTP_PACKET_SIZE; z++) - { - Serial.print(packetBuffer[z], HEX); - if (((z + 1) % 4) == 0) - { - Serial.println(); - } - } - Serial.println(); - - syslog.logf(LOG_INFO, " Received UDP packet size %d LI, Vers, Mode : 0x%02x Stratum: 0x%02x Polling: 0x%02x Precision: 0x%02x", packetSize, LIVNMODE, STRATUM, POLLING, PRECISION); -#endif - - packetBuffer[0] = 0b00100100; // LI, Version, Mode - if (gpsLocked) - { - packetBuffer[1] = 1; // stratum 1 if synced with GPS - } - else - { - packetBuffer[1] = 16; // stratum 16 if not synced - } - // think that should be at least 4 or so as you do not use fractional seconds - // packetBuffer[1] = 4; // stratum - packetBuffer[2] = 6; // polling minimum - packetBuffer[3] = 0xFA; // precision - - packetBuffer[4] = 0; // root delay - packetBuffer[5] = 0; - packetBuffer[6] = 8; - packetBuffer[7] = 0; - - packetBuffer[8] = 0; // root dispersion - packetBuffer[9] = 0; - packetBuffer[10] = 0xC; - packetBuffer[11] = 0; - - // int year; - // byte month, day, hour, minute, second, hundredths; - // unsigned long date, time, age; - uint32_t timestamp, tempval; - time_t t = now(); - - // gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age); - // timestamp = numberOfSecondsSince1900Epoch(year,month,day,hour,minute,second); - - // timestamp = numberOfSecondsSince1900Epoch(year(t), month(t), day(t), hour(t), minute(t), second(t)); - // Better, less verbose, more elegant timestamp calculation, suggested by cheise @ Github - 20230206 - timestamp = t + seventyYears; - -#ifdef DEBUG - Serial.println(timestamp); - // print_date(gps); -#endif - - tempval = timestamp; - - if (gpsLocked) - { - packetBuffer[12] = 71; //"G"; - packetBuffer[13] = 80; //"P"; - packetBuffer[14] = 83; //"S"; - packetBuffer[15] = 0; //"0"; - } - else - { - // Set refid to IP address if not locked - IPAddress myIP = WiFi.localIP(); - packetBuffer[12] = myIP[0]; - packetBuffer[13] = myIP[1]; - packetBuffer[14] = myIP[2]; - packetBuffer[15] = myIP[3]; - } - - // reference timestamp - packetBuffer[16] = (tempval >> 24) & 0XFF; - tempval = timestamp; - packetBuffer[17] = (tempval >> 16) & 0xFF; - tempval = timestamp; - packetBuffer[18] = (tempval >> 8) & 0xFF; - tempval = timestamp; - packetBuffer[19] = (tempval)&0xFF; - - packetBuffer[20] = 0; - packetBuffer[21] = 0; - packetBuffer[22] = 0; - packetBuffer[23] = 0; - - // copy originate timestamp from incoming UDP transmit timestamp - packetBuffer[24] = packetBuffer[40]; - packetBuffer[25] = packetBuffer[41]; - packetBuffer[26] = packetBuffer[42]; - packetBuffer[27] = packetBuffer[43]; - packetBuffer[28] = packetBuffer[44]; - packetBuffer[29] = packetBuffer[45]; - packetBuffer[30] = packetBuffer[46]; - packetBuffer[31] = packetBuffer[47]; - - // receive timestamp - packetBuffer[32] = (tempval >> 24) & 0XFF; - tempval = timestamp; - packetBuffer[33] = (tempval >> 16) & 0xFF; - tempval = timestamp; - packetBuffer[34] = (tempval >> 8) & 0xFF; - tempval = timestamp; - packetBuffer[35] = (tempval)&0xFF; - - packetBuffer[36] = 0; - packetBuffer[37] = 0; - packetBuffer[38] = 0; - packetBuffer[39] = 0; - - // transmitt timestamp - packetBuffer[40] = (tempval >> 24) & 0XFF; - tempval = timestamp; - packetBuffer[41] = (tempval >> 16) & 0xFF; - tempval = timestamp; - packetBuffer[42] = (tempval >> 8) & 0xFF; - tempval = timestamp; - packetBuffer[43] = (tempval)&0xFF; - - packetBuffer[44] = 0; - packetBuffer[45] = 0; - packetBuffer[46] = 0; - packetBuffer[47] = 0; - - // Reply to the IP address and port that sent the NTP request - - Udp.beginPacket(Remote, PortNum); - Udp.write(packetBuffer, NTP_PACKET_SIZE); - Udp.endPacket(); - } -} - -//////////////////////////////////////// - -void loop() -{ - FeedGpsParser(); // decode incoming GPS data - SyncCheck(); // synchronize to GPS or RTC - UpdateDisplay(); // if time has changed, display it - if (millis() - pps_blink_time > PPS_BLINK_INTERVAL) // If x milliseconds passed, then it's time to switch led off for blink effect - digitalWrite(PPS_LED, LOW); - server.handleClient(); - processNTP(); - processRFC868(); -} +// WiFi enabled GPS NTP server - Cristiano Monteiro - 06.May.2021 +// Based on the work of: +// Bruce E. Hall, W8BH - http://w8bh.net +// and +// https://forum.arduino.cc/u/ziggy2012/summary +// +// Contributions from: +// https://github.com/mmarkin +// https://github.com/sjthespian + +#include +#include +//#include + +// State data +#include + +// For time on the web page +#include // For formatting time + +// Needed for UDP functionality +#include +// Time Server Port +#define NTP_PORT 123 +static const int NTP_PACKET_SIZE = 48; +// buffers for receiving and sending data +byte packetBuffer[NTP_PACKET_SIZE]; +// An Ethernet UDP instance +WiFiUDP Udp; + +// Syslog support +#include + +// Main Web Page +// #include "index.h" +#include "index_bytearray.h" + +#if defined(ARDUINO_ARCH_ESP8266) +#include +#include +#include + +ESP8266WebServer server(80); +SoftwareSerial ss(D7, D8); // Serial GPS handler +#define PPS_LED 10 +#define LOCK_LED 0U // ESP8266 D3 +#define WIFI_BUTTON 2U // ESP8266 D4 +#elif defined(ESP32) +#include "WiFi.h" +#include +#include +// Web OTA Upgrade +#include + +HardwareSerial ss(2); +WebServer server(80); +#define PPS_LED 27 +#define LOCK_LED 19 +#define WIFI_BUTTON 5 + +// Priority tasks +// TaskHandle_t FGP; // FeedGPSParser +// TaskHandle_t SC; // SyncCheck +// TaskHandle_t PN; // ProcessNTP +// TaskHandle_t PR; // ProcessRFC868 + +// Required for temperature reading +#ifdef __cplusplus +extern "C" +{ +#endif + uint8_t temprature_sens_read(); +#ifdef __cplusplus +} +#endif +uint8_t temprature_sens_read(); +#else +#error Unknown architecture +#endif + +/* Create a WiFi access point and provide a web server on it. */ +#include +#include +#include // We will use clock's eeprom to store config + +// function prototypes +void processWifi(); // Need to declare this for handleUpdate() +void UpdateDisplay(); +void processKeyHold(); +void processKeyPress(); + +// GLOBAL DEFINES +#define HOSTNAME "ESP-Time-Server" // Hostname used for syslog and DHCP +#define WIFIRETRIES 15 // Max number of wifi retry attempts +//#define APSSID "GNSSTimeServer" // Default AP SSID +//#define APPSK "thereisnospoon" // Default password +#define PPS_PIN 12U // ESP8266 D6 - Pin on which 1PPS line is attached +#define SYNC_INTERVAL 10 // time, in seconds, between GPS sync attempts +#define SYNC_TIMEOUT 30 // time(sec) without GPS input before error +// #define RTC_UPDATE_INTERVAL SECS_PER_DAY // time(sec) between RTC SetTime events +#define RTC_UPDATE_INTERVAL 30 // time(sec) between RTC SetTime events +#define PPS_BLINK_INTERVAL 50 // Set time pps led should be on for blink effect +// #define SYSLOG_SERVER "x.x.x.x" // syslog server name or IP +#define SYSLOG_PORT 514 // syslog port + +const char *www_username = "admin"; +const char *www_password = "esp32"; +// allows you to set the realm of authentication Default:"Login Required" +const char *www_realm = "Custom Auth Realm"; +// the Content of the HTML response in case of Unautherized Access Default:empty +String authFailResponse = "Authentication Failed"; +const char *serverUpdate = "
"; + +#define WIFI_LED 14U // ESP8266 D5 +#define BTN_HOLD_MS 2000 // Number of milliseconds to determine button being held +#define BTN_NONE 0 // No button press +#define BTN_PRESS 1 // Button pressed for < BTN_HOLD_MS +#define BTN_HOLD 2 // Button held for at least BTN_HOLD_MS + +// INCLUDES +#include // Time functions https://github.com/PaulStoffregen/Time +#include // GPS parsing https://github.com/mikalhart/TinyGPSPlus +#include // OLED and DS3231 necessary +#include // RTC functions + +RtcDS3231 Rtc(Wire); +EepromAt24c32 RtcEeprom(Wire); + +// U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE); // OLED display library parameters +U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE); // OLED display library parameters + +TinyGPSPlus gps; + +time_t displayTime = 0; // time that is currently displayed +time_t syncTime = 0; // time of last GPS or RTC synchronization +time_t lastSetRTC = 0; // time that RTC was last set +volatile int pps = 0; // GPS one-pulse-per-second flag +time_t dstStart = 0; // start of DST in unix time +time_t dstEnd = 0; // end of DST in unix time +bool gpsLocked = false; // indicates recent sync with GPS +bool buttonPressed = false; // To process button presses outside the ISR +int currentYear = 0; // used for DST +int displaynum = 0; // Display pane currently displayed +#define NUMDISPLAYPANES 2 // Number of display panes available + +long int pps_blink_time = 0; + +/* Set these to your desired credentials. */ +const char *ssid = "GNSSTimeServer"; +const char *password = "thereisnospoon"; +String wifissid; +String wifipassword; +String syslogserver; +uint8_t statusWifi = 1; + +// rdate server +WiFiServer RFC868server(37); + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP udpClient; +// Create syslogt instance with LOG_DAEMON +// Create a new empty syslog instance +Syslog syslog(udpClient, SYSLOG_PROTO_IETF); +/* + * ISR Debounce + */ + +// use 150ms debounce time +#define DEBOUNCE_TICKS 100 + +word keytick_down = 0; // record time of keypress +word keytick_up = 0; +int lastState = HIGH; // record last button state to support debouncing + +//#define DEBUG // Comment this in order to remove debug code from release version +//#define DEBUG_GPS // Uncomment this to receive GPS messages in debug output + +#ifdef DEBUG +#if defined(ARDUINO_ARCH_ESP8266) +#define DEBUG_PRINT(x) Serial.print(x) +#define DEBUG_PRINTDEC(x) Serial.print(x, DEC) +#define DEBUG_PRINTLN(x) Serial.println(x) +#elif defined(ESP32) +#define DEBUG_PRINT(x) Serial.print(String(xPortGetCoreID()) + " - " + String(x)) +#define DEBUG_PRINTDEC(x) Serial.print(x, DEC) +#define DEBUG_PRINTLN(x) Serial.println(String(xPortGetCoreID()) + " - " + String(x)) + // #define DEBUG_PRINT(x) Serial.print(x) + // #define DEBUG_PRINTDEC(x) Serial.print(x, DEC) + // #define DEBUG_PRINTLN(x) Serial.println(x) +#else +#error Unknown architecture +#endif +#else +#define DEBUG_PRINT(x) +#define DEBUG_PRINTDEC(x) +#define DEBUG_PRINTLN(x) +#endif + +// Button ISR debouncing routine + +// returns true if key pressed + +void KeyCheck() +{ + // Button pressed and released + int button_type = 0; + if (keytick_up > 0 and keytick_down > 0 and ((keytick_down - keytick_up) >= DEBOUNCE_TICKS)) + { + if ((keytick_down - keytick_up) > BTN_HOLD_MS) + { + button_type = BTN_HOLD; + } + else + { + button_type = BTN_PRESS; + } + + // return button_type; + switch (button_type) + { + case BTN_HOLD: // Malabarism to cover mechanical switch debouncing + processKeyHold(); + break; + case BTN_PRESS: + processKeyPress(); + break; + } + } + // return BTN_NONE; +} + +// littleFS routines + +String readData(const char *filename) +{ + DEBUG_PRINT("Reading data from "); + DEBUG_PRINT(filename); + File file = LittleFS.open(filename, "r"); + + String data = ""; + if (!file) + { + DEBUG_PRINTLN("ERROR: File open failed!"); + } + else + { + + if (file.available()) + { + data = file.readString(); + } + DEBUG_PRINT(" : "); + DEBUG_PRINTLN(data); + + file.close(); + } + + return data; +} + +void writeData(const char *filename, String data) +{ + DEBUG_PRINT("Writing data to "); + DEBUG_PRINT(filename); + File file = LittleFS.open(filename, "w"); + + if (!file) + { + DEBUG_PRINTLN("ERROR: File open failed!"); + } + else + { + file.println(data); + DEBUG_PRINT(" : "); + DEBUG_PRINTLN(data); + } + + file.close(); +} + +// WiFi and Web Routines + +void handleUpdate() +{ + if (!server.authenticate(www_username, www_password)) + { + return server.requestAuthentication(DIGEST_AUTH, www_realm, authFailResponse); + } + wifissid = server.arg("wifi_ssid"); + wifipassword = server.arg("wifi_psk"); + syslogserver = server.arg("syslog_server"); + DEBUG_PRINTLN("Settings Updated!"); + DEBUG_PRINTLN(wifissid); + // DEBUG_PRINTLN(wifipassword); + // Save SSID and password in littlefs + writeData("/wifissid", wifissid); + if (wifipassword != "") + writeData("/wifipsk", wifipassword); + writeData("/syslogserver", syslogserver); + + processWifi(); + + String content = "Return to main page"; + server.send(200, "text/html", content); +} + +void timeToString(char *string, size_t size, int seconds) +{ + int days = seconds / 86400; + seconds %= 86400; + byte hours = seconds / 3600; + seconds %= 3600; + byte minutes = seconds / 60; + seconds %= 60; + snprintf(string, size, "%04d:%02d:%02d:%02d", days, hours, minutes, seconds); +} + +String getMacAddress(int mt) +{ + uint8_t baseMac[6] = {0}; + +// Get MAC address for WiFi station +// ESP_MAC_WIFI_SOFTAP +// ESP_MAC_WIFI_STA +#if defined(ESP32) + esp_read_mac(baseMac, ESP_MAC_WIFI_STA); +#endif + + char baseMacChr[18] = {0}; + sprintf(baseMacChr, "%02X:%02X:%02X:%02X:%02X:%02X", baseMac[0], baseMac[1], baseMac[2], baseMac[3], baseMac[4], baseMac[5]); + + String macAddress = String(baseMacChr); + // Serial.println(baseMacChr); + return macAddress; +} + +// String getSSID() { +// wifi_config_t conf; +// esp_wifi_get_config(WIFI_IF_STA, &conf); +// return String(reinterpret_cast(conf.sta.ssid)); +// } + +String convS(const char * a) { + int i; + + String res = ""; + i = 0; + while (a[i]!='\0') { + //for (i = 0; i < arr_size; i++) { + res = res + a[i]; + i++; + } + return res; +} + +// void handleRoot() +void handleJSON() +{ + syslog.logf(LOG_INFO, "JSON requested from %s", server.client().remoteIP().toString().c_str()); + + char webpage[2048]; + char timestr[32]; + + // Build string for web UI + time_t t = now(); // get current time + tm *ptm = gmtime(&t); + strftime(timestr, 32, "%Y-%m-%d %H:%M:%S UTC", ptm); + + int sats = (gps.satellites.value() != 255) ? gps.satellites.value() : 0; + String resol = gpsLocked ? String(gps.hdop.value()) : ""; + + // latitude & longitude + float lat = 0.0; + float lng = 0.0; + if (gpsLocked) + { + lat = gps.location.lat(); + lng = gps.location.lng(); + } + + IPAddress myIP = WiFi.localIP(); + if (myIP[0] == 0) + myIP = WiFi.softAPIP(); + + String wifinet = ""; + String mcaddr = ""; + String wifmode = ""; + int signal = 0; + if (WiFi.getMode() == WIFI_STA) + { + wifmode = "Station"; + wifinet = wifissid; + signal = WiFi.RSSI(); +#if defined(ESP32) + mcaddr = getMacAddress(ESP_MAC_WIFI_STA); +#endif + } + else + { + wifmode = "Access Point"; + wifinet = convS(ssid); + signal = 0; +#if defined(ESP32) + mcaddr = getMacAddress(ESP_MAC_WIFI_SOFTAP); +#endif + } + +char uptime[15] = ""; +#if defined(ESP32) + timeToString(uptime, sizeof(uptime), esp_timer_get_time() / 1000000); +#endif + + String uptimeStr(uptime); + + int freeHeap = 0; + int minimumHeap = 0; + String idfVersion = ""; + float internalTemp = 0.0; +#if defined(ESP32) + freeHeap = esp_get_free_heap_size() / 1024; + minimumHeap = esp_get_minimum_free_heap_size() / 1024; + idfVersion = esp_get_idf_version(); + internalTemp = (temprature_sens_read() - 32) / 1.8; // Temp is only correctly captured when WiFi active, ottherwise will always return 128 F (53.33 C) +#endif + + String locked = gpsLocked ? "True" : "False"; + + // RTC Data + String validDateTime = Rtc.IsDateTimeValid() ? "True" : "False"; + String isRTCRunning = Rtc.GetIsRunning() ? "True" : "False"; + // RtcDateTime Now = Rtc.GetDateTime(); + int8_t AgingOffset = Rtc.GetAgingOffset(); + float RTCTemperature = Rtc.GetTemperature().AsFloatDegC(); + + sprintf(webpage, + "{\"version\":\"%s\", \"uptime\":\"%s\", \"freeheap\":\"%d\", \"ip\":\"%s\", \"network\":\"%s\", \"type\":\"%s\",\ + \"signal\":\"%d\", \"timestamp\":\"%s\", \"lat\":\"%7.8f\", \"lon\":\"%7.8f\", \"sats\":\"%d\", \"hdop\":\"%s\",\ + \"syslog\":\"%s\", \"ssid\":\"%s\", \"minimumheap\":\"%d\", \"idfversion\":\"%s\", \"internaltemp\":\"%.1f\",\ + \"macaddress\":\"%s\", \"locked\":\"%s\", \"validdatetime\":\"%s\", \"rtcrunning\":\"%s\", \"agingoffset\":\"%d\",\ + \"rtctemperature\":\"%.1f\"}", + "2.0h", + uptimeStr.c_str(), + freeHeap, + myIP.toString().c_str(), + wifinet.c_str(), + wifmode, + signal, + timestr, + (float)lat, + (float)lng, + sats, + resol, + syslogserver.c_str(), + wifissid.c_str(), + minimumHeap, + idfVersion, + internalTemp, + mcaddr.c_str(), + locked, + validDateTime, + isRTCRunning, + AgingOffset, + RTCTemperature); + server.send(200, "text/html", webpage); +} + +void handleRoot() +{ + const char *dataType = "text/html"; + + syslog.logf(LOG_INFO, "Webpage requested from %s", server.client().remoteIP().toString().c_str()); + + server.sendHeader(F("Content-Encoding"), F("gzip")); + +#if defined(ARDUINO_ARCH_ESP8266) + server.send(200, dataType, (const char *)index_gz, index_gz_len); +#elif defined(ESP32) + server.send_P(200, dataType, (const char *)index_gz, index_gz_len); +#else +#error Unknown architecture +#endif + // server.send(200, "text/html", PAGE_Index); +} + +void startHttpServer() +{ + server.on("/", handleRoot); + server.on("/updatewifi", handleUpdate); + server.on("/json", handleJSON); +#if defined(ESP32) + server.on("/serverUpdate", HTTP_GET, []() + { + if (!server.authenticate(www_username, www_password)) + { + return server.requestAuthentication(DIGEST_AUTH, www_realm, authFailResponse); + } + server.sendHeader("Connection", "close"); + server.send(200, "text/html", serverUpdate); }); + /*handling uploading firmware file */ + server.on( + "/update", HTTP_POST, []() + { + if (!server.authenticate(www_username, www_password)) + { + return server.requestAuthentication(DIGEST_AUTH, www_realm, authFailResponse); + } + server.sendHeader("Connection", "close"); + server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); + ESP.restart(); }, + []() + { + if (!server.authenticate(www_username, www_password)) + { + return server.requestAuthentication(DIGEST_AUTH, www_realm, authFailResponse); + } + HTTPUpload &upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) + { + // Serial.printf("Update: %s\n", upload.filename.c_str()); + if (!Update.begin(UPDATE_SIZE_UNKNOWN)) + { // start with max available size + // Update.printError(Serial); + } + } + else if (upload.status == UPLOAD_FILE_WRITE) + { + /* flashing firmware to ESP*/ + if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) + { + // Update.printError(Serial); + } + } + else if (upload.status == UPLOAD_FILE_END) + { + if (Update.end(true)) + { // true to set the size to the current progress + // Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + } + else + { + // Update.printError(Serial); + } + } + }); +#endif + server.begin(); + DEBUG_PRINTLN(F("HTTP server started")); + syslog.log(LOG_INFO, "HTTP server started"); +} + +void enableWifiAP() +{ + // WiFi Initialization as an AP + /* You can remove the password parameter if you want the AP to be open. */ + WiFi.mode(WIFI_AP); +// WiFi.softAP(ssid, psk, channel, hidden, max_connection) +// Setting maximum of 8 clients, 1 is default channel already, 0 is false for hidden SSID - The maximum allowed by ES8266 is 8 - Thanks to Mitch Markin for that +// ESP32 got a 10 as maximum +#if defined(ARDUINO_ARCH_ESP8266) + WiFi.softAP(ssid, password, 1, 0, 8); +#elif defined(ESP32) + WiFi.softAP(ssid, password, 1, 0, 10); +#else +#error Unknown architecture +#endif + +#ifdef DEBUG + IPAddress myIP = WiFi.softAPIP(); + DEBUG_PRINT(F("AP IP address: ")); + DEBUG_PRINTLN(myIP); +#endif + startHttpServer(); +} + +void enableWifi() +{ + // Get SSID and password from littleFS + wifissid = readData("/wifissid"); + wifipassword = readData("/wifipsk"); // Password follows + + wifissid.trim(); + wifipassword.trim(); + // Connect to WiFi + WiFi.setHostname(HOSTNAME); + WiFi.mode(WIFI_STA); + DEBUG_PRINTLN("Connecting to WiFI"); + DEBUG_PRINTLN(wifissid); + DEBUG_PRINTLN(wifipassword); +#if defined(ARDUINO_ARCH_ESP8266) + WiFi.begin(wifissid, wifipassword); +#elif defined(ESP32) + WiFi.begin(wifissid.c_str(), wifipassword.c_str()); +#else +#error Unknown architecture +#endif + + int retries = 0; + while ((WiFi.status() != WL_CONNECTED) && (retries < WIFIRETRIES)) + { + retries++; + delay(500); + DEBUG_PRINT("."); + } + if (retries >= WIFIRETRIES) + { + enableWifiAP(); + } + if (WiFi.status() == WL_CONNECTED) + { +#ifdef DEBUG + IPAddress myIP = WiFi.localIP(); + if (myIP[0] == 0) + myIP = WiFi.softAPIP(); + DEBUG_PRINTLN(F("WiFi connected!")); + DEBUG_PRINT("IP address: "); + DEBUG_PRINTLN(myIP); + syslog.logf(LOG_INFO, "WiFi connected as %s", myIP.toString().c_str()); +#endif + startHttpServer(); + } +} + +void disableWifi() +{ + server.stop(); + DEBUG_PRINTLN(F("HTTP server stopped")); + syslog.log(LOG_WARNING, "WiFi disabled!"); + if (WiFi.getMode() == WIFI_AP) + { + WiFi.softAPdisconnect(true); + WiFi.enableAP(false); + } + WiFi.mode(WIFI_OFF); + +#if defined(ARDUINO_ARCH_ESP8266) + WiFi.forceSleepBegin(); +#elif defined(ESP32) +#else +#error Unknown architecture +#endif + + DEBUG_PRINTLN(F("WiFi disabled")); +} + +void processWifi() +{ + // Toggle WiFi on/off and corresponding LED + DEBUG_PRINT(F("Status Wifi: ")); + DEBUG_PRINTLN(statusWifi); + + if (statusWifi) + { + enableWifi(); + digitalWrite(WIFI_LED, HIGH); + } + else + { + disableWifi(); + digitalWrite(WIFI_LED, LOW); + } +} + +// -------------------------------------------------------------------------------------------------- +// SERIAL MONITOR ROUTINES +// These routines print the date/time information to the serial monitor +// Serial monitor must be initialized in setup() before calling + +void PrintDigit(int d) +{ + if (d < 10) + DEBUG_PRINT('0'); + DEBUG_PRINT(d); +} + +void PrintTime(time_t t) +// display time and date to serial monitor +{ + PrintDigit(month(t)); + DEBUG_PRINT("-"); + PrintDigit(day(t)); + DEBUG_PRINT("-"); + PrintDigit(year(t)); + DEBUG_PRINT(" "); + PrintDigit(hour(t)); + DEBUG_PRINT(":"); + PrintDigit(minute(t)); + DEBUG_PRINT(":"); + PrintDigit(second(t)); + DEBUG_PRINTLN(" UTC"); +} + +// -------------------------------------------------------------------------------------------------- +// RTC SUPPORT +// These routines add the ability to get and/or set the time from an attached real-time-clock module +// such as the DS1307 or the DS3231. The module should be connected to the I2C pins (SDA/SCL). + +void PrintRTCstatus() +// send current RTC information to serial monitor +{ + RtcDateTime Now = Rtc.GetDateTime(); +#if defined(ARDUINO_ARCH_ESP8266) + // Deprecated on ESP32 + time_t t = Now.Epoch32Time(); +#elif defined(ESP32) + time_t t = Now.Unix32Time(); +#else +#error Unknown architecture +#endif + + if (t) + { + DEBUG_PRINT("PrintRTCstatus: "); + DEBUG_PRINTLN("Called PrintTime from PrintRTCstatus"); +#ifdef DEBUG + PrintTime(t); +#endif + } + else + { + DEBUG_PRINTLN("ERROR: cannot read the RTC."); + syslog.log(LOG_ERR, "ERROR: cannot read the RTC."); + } +} + +// Update RTC from current system time +void SetRTC(time_t t) +{ + RtcDateTime timeToSet; + +#if defined(ARDUINO_ARCH_ESP8266) + // Deprecated on ESP32 + timeToSet.InitWithEpoch32Time(t); +#elif defined(ESP32) + timeToSet.InitWithUnix32Time(t); +#else +#error Unknown architecture +#endif + + Rtc.SetDateTime(timeToSet); + if (Rtc.LastError() == 0) + { + DEBUG_PRINT("SetRTC: "); + DEBUG_PRINTLN("Called PrintTime from SetRTC"); +#ifdef DEBUG + PrintTime(t); +#endif + } + else + { + DEBUG_PRINT("ERROR: cannot set RTC time"); + syslog.log(LOG_ERR, "ERROR: cannot set RTC time"); + } +} + +void ManuallySetRTC() +// Use this routine to manually set the RTC to a specific UTC time. +// Since time is automatically set from GPS, this routine is mainly for +// debugging purposes. Change numeric constants to the time desired. +{ + // tmElements_t tm; + // tm.Year = 2017 - 1970; // Year in unix years + // tm.Month = 5; + // tm.Day = 31; + // tm.Hour = 5; + // tm.Minute = 59; + // tm.Second = 30; + // SetRTC(makeTime(tm)); // set RTC to desired time +} + +void UpdateRTC() +// keep the RTC time updated by setting it every (RTC_UPDATE_INTERVAL) seconds +// should only be called when system time is known to be good, such as in a GPS sync event +{ + time_t t = now(); // get current time + if ((t - lastSetRTC) >= RTC_UPDATE_INTERVAL) // is it time to update RTC internal clock? + { + DEBUG_PRINT("Called SetRTC from UpdateRTC with "); + DEBUG_PRINTLN(t); + SetRTC(t); // set RTC with current time + lastSetRTC = t; // remember time of this event + } +} + +// -------------------------------------------------------------------------------------------------- +// LCD SPECIFIC ROUTINES +// These routines are used to display time and/or date information on the LCD display +// Assumes the presence of a global object "lcd" of the type "LiquidCrystal" like this: +// LiquidCrystal lcd(6,9,10,11,12,13); +// where the six numbers represent the digital pin numbers for RS,Enable,D4,D5,D6,and D7 LCD pins + +void ShowDate(time_t t) +{ + String data = ""; + + int y = year(t); + if (y < 10) + data = data + "0"; + data = data + String(y) + "-"; + + int m = month(t); + if (m < 10) + data = data + "0"; + data = data + String(m) + "-"; + + int d = day(t); + if (d < 10) + data = data + "0"; + data = data + String(d); + + u8g2.setFont(u8g2_font_open_iconic_all_2x_t); + u8g2.drawGlyph(0, 43, 107); + + u8g2.setFont(u8g2_font_logisoso16_tf); // choose a suitable font + u8g2.drawStr(18, 43, data.c_str()); + + DEBUG_PRINTLN("UpdateDisplay"); +} + +void ShowTime(time_t t) +{ + String hora = ""; + int h = hour(t); + if (h < 10) + hora = hora + "0"; + hora = hora + String(h) + ":"; + + int m = minute(t); + if (m < 10) + hora = hora + "0"; + hora = hora + String(m) + ":"; + + int s = second(t); + if (s < 10) + hora = hora + "0"; + hora = hora + String(s) + " UTC"; + + u8g2.setFont(u8g2_font_open_iconic_all_2x_t); + u8g2.drawGlyph(0, 64, 123); + + u8g2.setFont(u8g2_font_logisoso16_tf); // choose a suitable font + u8g2.drawStr(16, 64, hora.c_str()); +} + +void ShowDateTime(time_t t) +{ + ShowDate(t); + + ShowTime(t); +} + +void ShowSyncFlag() +{ + String sats = ""; + if (gps.satellites.value() != 255) + sats = String(gps.satellites.value()); + else + sats = "0"; + + if (gpsLocked) + digitalWrite(LOCK_LED, HIGH); + // else + // digitalWrite(LOCK_LED, LOW); + + String resol = ""; + if (gpsLocked) + resol = String(gps.hdop.value()); + else + resol = "0"; + + u8g2.setFont(u8g2_font_open_iconic_all_2x_t); + u8g2.drawGlyph(0, 16, 259); + u8g2.drawGlyph(64, 16, 263); + + u8g2.setFont(u8g2_font_logisoso16_tf); // choose a suitable font + u8g2.drawStr(18, 16, sats.c_str()); + u8g2.drawStr(82, 16, resol.c_str()); +} + +void ShowWifiNetwork() +{ + String wifinet = ""; + + if (WiFi.getMode() == WIFI_STA) + wifinet = wifissid; + else + wifinet = convS(ssid); + + u8g2.setFont(u8g2_font_open_iconic_all_2x_t); + u8g2.drawGlyph(0, 43, 248); + + int wrap = 38; + int ypos1 = 28; + int ypos2 = 43; + // Play games with the font and spacing based on the length of the SSID + if (wifinet.length() > 30) + { + u8g2.setFont(u8g2_font_6x12_tf); // Small font for long SSID + wrap = 18; + } + else if (wifinet.length() > 20) + { + u8g2.setFont(u8g2_font_7x13_tf); // Not quite as small + wrap = 15; + } + else if (wifinet.length() > 11) + { + u8g2.setFont(u8g2_font_7x13_tf); // Not quite as small on one line + ypos1 = 43; + } + else + { + u8g2.setFont(u8g2_font_10x20_tf); // Readable on one line + ypos1 = 43; + } + u8g2.drawStr(16, ypos1, wifinet.substring(0, wrap).c_str()); + if (wifinet.length() > 20) // 2nd line needed if > 20 + u8g2.drawStr(16, ypos2, wifinet.substring(wrap).c_str()); +} + +void ShowIPAddress() +{ + IPAddress myIP = WiFi.localIP(); + if (myIP[0] == 0) + myIP = WiFi.softAPIP(); + + u8g2.setFont(u8g2_font_logisoso16_tr); // choose a suitable font + u8g2.drawStr(0, 64, myIP.toString().c_str()); +} + +void InitLCD() +{ + u8g2.begin(); // Initialize OLED library +} + +// -------------------------------------------------------------------------------------------------- +// TIME SYNCHONIZATION ROUTINES +// These routines will synchonize time with GPS and/or RTC as necessary +// Sync with GPS occur when the 1pps interrupt signal from the GPS goes high. +// GPS synchonization events are attempted every (SYNC_INTERVAL) seconds. +// If a valid GPS signal is not received within (SYNC_TIMEOUT) seconds, the clock with synchonized +// with RTC instead. The RTC time is updated with GPS data once every 24 hours. + +void SyncWithGPS() +{ + int y; + // byte h, m, s, mon, d, hundredths; + byte h, m, s, mon, d; + unsigned long age; + y = gps.date.year(); + mon = gps.date.month(); + d = gps.date.day(); + h = gps.time.hour(); + m = gps.time.minute(); + s = gps.time.second(); + age = gps.location.age(); + // gps.crack_datetime(&y, &mon, &d, &h, &m, &s, NULL, &age); // get time from GPS + // cheise @ Github spotted the uneccessary and wrong '> 3000' condition. Fixed - 20230206 + // if (age < 1000 or age > 3000) + if (age < 1000) // dont use data older than 1 second + { + setTime(h, m, s, d, mon, y); // copy GPS time to system time + DEBUG_PRINT("Time from GPS: "); + DEBUG_PRINT(h); + DEBUG_PRINT(":"); + DEBUG_PRINT(m); + DEBUG_PRINT(":"); + DEBUG_PRINTLN(s); + adjustTime(1); // 1pps signal = start of next second + syncTime = now(); // remember time of this sync + if (!gpsLocked) + { + syslog.logf(LOG_INFO, "GPS sychronized - %d satellites", gps.satellites.value()); + } + gpsLocked = true; // set flag that time is reflects GPS time + UpdateRTC(); // update internal RTC clock periodically + DEBUG_PRINTLN("GPS synchronized"); // send message to serial monitor + } + else + { + DEBUG_PRINT("Age: "); + DEBUG_PRINTLN(age); + } +} + +void SyncWithRTC() +{ + RtcDateTime time = Rtc.GetDateTime(); +#if defined(ARDUINO_ARCH_ESP8266) + // Deprecated on ESP32 + long int a = time.Epoch32Time(); +#elif defined(ESP32) + long int a = time.Unix32Time(); +#else +#error Unknown architecture +#endif + setTime(a); // set system time from RTC + DEBUG_PRINT("SyncFromRTC: "); + DEBUG_PRINTLN(a); + syncTime = now(); // and remember time of this sync event + DEBUG_PRINTLN("Synchronized from RTC"); // send message to serial monitor +} + +#if defined(ARDUINO_ARCH_ESP8266) +void SyncCheck() +{ +#elif defined(ESP32) +void SyncCheck(void *parameter) +{ + for (;;) + { +#else +#error Unknown architecture +#endif + // Manage synchonization of clock to GPS module + // First, check to see if it is time to synchonize + // Do time synchonization on the 1pps signal + // This call must be made frequently (keep in main loop) + // DEBUG_PRINTLN(F("SyncCheck Task Running...")); + // Serial.println("2SyncCheck Task Running..."); + unsigned long timeSinceSync = now() - syncTime; // how long has it been since last sync? + if (pps && (timeSinceSync >= SYNC_INTERVAL)) + { // is it time to sync with GPS yet? + DEBUG_PRINTLN("Called SyncWithGPS from SyncCheck"); + SyncWithGPS(); // yes, so attempt it. + } + pps = 0; // reset 1-pulse-per-second flag, regardless + if (timeSinceSync >= SYNC_TIMEOUT) // GPS sync has failed + { + if (gpsLocked) + { + syslog.log(LOG_INFO, "GPS sych lost!"); + } + gpsLocked = false; // flag that clock is no longer in GPS sync + DEBUG_PRINTLN("Called SyncWithRTC from SyncCheck"); + SyncWithRTC(); // sync with RTC instead + } +#if defined(ESP32) + vTaskDelay(1); + // taskYIELD(); +} +#endif +} + +// -------------------------------------------------------------------------------------------------- +// MAIN PROGRAM + +void IRAM_ATTR isr() // INTERRUPT SERVICE REQUEST +{ + pps = 1; // Flag the 1pps input signal + digitalWrite(PPS_LED, HIGH); // Ligth up led pps monitor + pps_blink_time = millis(); // Capture time in order to turn led off so we can get the blink effect ever x milliseconds - On loop + // DEBUG_PRINTLN("pps"); Sometimes cause: esp32 Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1). +} + +// Handle button pressed interrupt +void IRAM_ATTR btw() // INTERRUPT SERVICE REQUEST +{ + int currentState = digitalRead(WIFI_BUTTON); + if ((currentState != lastState) and (!buttonPressed)) + { + if (lastState == HIGH) + { + keytick_up = millis(); + } + else + { + keytick_down = millis(); + buttonPressed = true; + // KeyCheck(); + } + lastState = currentState; + } + // DEBUG_PRINTLN(F("BUTTON PRESSED!")); Sometimes cause: esp32 Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1). +} + +void processKeyHold() +{ + if (statusWifi) + statusWifi = 0; + else + statusWifi = 1; + + processWifi(); + DEBUG_PRINTLN(F("BUTTON HOLD PROCESSED!")); +} + +void processKeyPress() +{ + DEBUG_PRINTLN(F("BUTTON CLICK PROCESSED!")); + displaynum++; + if (displaynum >= NUMDISPLAYPANES) + { + displaynum = 0; + } + UpdateDisplay(); +} + +#if defined(ARDUINO_ARCH_ESP8266) +void FeedGpsParser() +{ +#elif defined(ESP32) + void FeedGpsParser(void *parameter) + { + for (;;) + { +#else +#error Unknown architecture +#endif + // feed currently available data from GPS module into tinyGPS parser + // unsigned long StartTime = millis(); + while (ss.available()) // look for data from GPS module + { + char c = ss.read(); // read in all available chars + gps.encode(c); // and feed chars to GPS parser + // Serial.write(c); // Uncomment for some extra debug info if in doubt about GPS feed +#ifdef DEBUG_GPS + DEBUG_PRINT(c); +#endif + // Will toggle LOCK_LED at each pass if not locked, so user can see the GPS is actually doing something + if (!gpsLocked) + digitalWrite(LOCK_LED, !digitalRead(LOCK_LED)); + // Serial.print(c); + } + // DEBUG_PRINTLN(millis() - StartTime); +#if defined(ESP32) + vTaskDelay(1); + // taskYIELD(); +} +#endif +} + +void UpdateDisplay() +// Call this from the main loop +// Updates display if time has changed +{ + time_t t = now(); // get current time + if (t != displayTime) // has time changed? + { + u8g2.clearBuffer(); // Clear buffer contents + switch (displaynum) + { + case 0: + ShowDateTime(t); // Display the new UTC time + ShowSyncFlag(); // show if display is in GPS sync + break; + case 1: + ShowWifiNetwork(); + ShowIPAddress(); + break; + } + u8g2.sendBuffer(); // Send new information to display + + displayTime = t; // save current display value + DEBUG_PRINTLN("Called PrintTime from UpdateDisplay"); +#ifdef DEBUG + PrintTime(t); // copy time to serial monitor +#endif + } +} + +//////////////////////////////////////// + +const uint8_t daysInMonth[] PROGMEM = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // const or compiler complains + +const unsigned long seventyYears = 2208988800UL; // to convert unix time to epoch + +// Replaced with better, less verbose, more elegant timestamp = t + seventyYears calculation, suggested by cheise @ Github - 20230206 +// NTP since 1900/01/01 +// static unsigned long int numberOfSecondsSince1900Epoch(uint16_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t mm, uint8_t s) +// { +// if (y >= 1970) +// y -= 1970; +// uint16_t days = d - 1; +// for (uint8_t i = 1; i < m; ++i) +// days += pgm_read_byte(daysInMonth + i - 1); +// if (m > 2 && y % 4 == 0) +// ++days; +// days += 365 * y + (y + 3) / 4 - 1; +// return days * 24L * 3600L + h * 3600L + mm * 60L + s + seventyYears; +// } + +//////////////////////////////////////// + +// Process rdate request +// Return the time as the number of seconds since 1/1/1900 +#if defined(ARDUINO_ARCH_ESP8266) +void processRFC868() +{ +#elif defined(ESP32) + void processRFC868(void *parameter) + { + for (;;) + { +#else +#error Unknown architecture +#endif + // DEBUG_PRINTLN(F("Reached processRFC868")); + uint32_t timestamp; + WiFiClient client = RFC868server.accept(); + // client.setNoDelay(true); // Unecessary for UDP + if (client.connected()) + { + // syslog.logf(LOG_INFO, "RDATE request from %s", client.remoteIP().toString().c_str()); + // Serial.println(client.remoteIP().toString().c_str()); + + // Send Data to connected client + time_t t = now(); // get current time + + timestamp = t + seventyYears; + + uint8_t bytes[4]; + + // Populate big endian byte array + bytes[0] = (timestamp >> 24) & 0xFF; + bytes[1] = (timestamp >> 16) & 0xFF; + bytes[2] = (timestamp >> 8) & 0xFF; + bytes[3] = (timestamp >> 0) & 0xFF; + + client.write((const uint8_t *)bytes, sizeof(timestamp)); + // Serial.println(timestamp); + + // Disconnect client + client.stop(); + } +#if defined(ESP32) + vTaskDelay(1); + // taskYIELD(); +} +#endif +} + +#if defined(ARDUINO_ARCH_ESP8266) +void processNTP() +{ +#elif defined(ESP32) + void processNTP(void *parameter) + { + for (;;) + { +#else +#error Unknown architecture +#endif + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) + { + Udp.read(packetBuffer, NTP_PACKET_SIZE); + IPAddress Remote = Udp.remoteIP(); + int PortNum = Udp.remotePort(); + // Packets bigger than NTP_PACKET size (like the ones generated by ntpq -c sysinfo , which is 136 bytes) will block the UDP instance if not flushed. Not ready to deal with them right now, maybe in the future. Need to flush the remaining bytes. + Udp.flush(); + +#ifdef DEBUG + Serial.println(); + DEBUG_PRINTLN(F("Received UDP packet size ")); + Serial.println(packetSize); + Serial.print("From "); + + for (int i = 0; i < 4; i++) + { + Serial.print(Remote[i], DEC); + if (i < 3) + { + Serial.print("."); + } + } + Serial.print(", port "); + Serial.print(PortNum); + + byte LIVNMODE = packetBuffer[0]; + Serial.print(" LI, Vers, Mode :"); + Serial.print(LIVNMODE, HEX); + + byte STRATUM = packetBuffer[1]; + Serial.print(" Stratum :"); + Serial.print(STRATUM, HEX); + + byte POLLING = packetBuffer[2]; + Serial.print(" Polling :"); + Serial.print(POLLING, HEX); + + byte PRECISION = packetBuffer[3]; + Serial.print(" Precision :"); + Serial.println(PRECISION, HEX); + + for (int z = 0; z < NTP_PACKET_SIZE; z++) + { + Serial.print(packetBuffer[z], HEX); + if (((z + 1) % 4) == 0) + { + Serial.println(); + } + } + Serial.println(); + + syslog.logf(LOG_INFO, " Received UDP packet size %d LI, Vers, Mode : 0x%02x Stratum: 0x%02x Polling: 0x%02x Precision: 0x%02x", packetSize, LIVNMODE, STRATUM, POLLING, PRECISION); +#endif + + packetBuffer[0] = 0b00100100; // LI, Version, Mode + if (gpsLocked) + { + packetBuffer[1] = 1; // stratum 1 if synced with GPS + } + else + { + packetBuffer[1] = 16; // stratum 16 if not synced + } + // think that should be at least 4 or so as you do not use fractional seconds + // packetBuffer[1] = 4; // stratum + packetBuffer[2] = 6; // polling minimum + packetBuffer[3] = 0xFA; // precision + + packetBuffer[4] = 0; // root delay + packetBuffer[5] = 0; + packetBuffer[6] = 8; + packetBuffer[7] = 0; + + packetBuffer[8] = 0; // root dispersion + packetBuffer[9] = 0; + packetBuffer[10] = 0xC; + packetBuffer[11] = 0; + + // int year; + // byte month, day, hour, minute, second, hundredths; + // unsigned long date, time, age; + uint32_t timestamp, tempval; + time_t t = now(); + + // gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age); + // timestamp = numberOfSecondsSince1900Epoch(year,month,day,hour,minute,second); + + // timestamp = numberOfSecondsSince1900Epoch(year(t), month(t), day(t), hour(t), minute(t), second(t)); + // Better, less verbose, more elegant timestamp calculation, suggested by cheise @ Github - 20230206 + timestamp = t + seventyYears; + +#ifdef DEBUG + Serial.println(timestamp); + // print_date(gps); +#endif + + tempval = timestamp; + + if (gpsLocked) + { + packetBuffer[12] = 71; //"G"; + packetBuffer[13] = 80; //"P"; + packetBuffer[14] = 83; //"S"; + packetBuffer[15] = 0; //"0"; + } + else + { + // Set refid to IP address if not locked + IPAddress myIP = WiFi.localIP(); + packetBuffer[12] = myIP[0]; + packetBuffer[13] = myIP[1]; + packetBuffer[14] = myIP[2]; + packetBuffer[15] = myIP[3]; + } + + // reference timestamp + packetBuffer[16] = (tempval >> 24) & 0XFF; + tempval = timestamp; + packetBuffer[17] = (tempval >> 16) & 0xFF; + tempval = timestamp; + packetBuffer[18] = (tempval >> 8) & 0xFF; + tempval = timestamp; + packetBuffer[19] = (tempval)&0xFF; + + packetBuffer[20] = 0; + packetBuffer[21] = 0; + packetBuffer[22] = 0; + packetBuffer[23] = 0; + + // copy originate timestamp from incoming UDP transmit timestamp + packetBuffer[24] = packetBuffer[40]; + packetBuffer[25] = packetBuffer[41]; + packetBuffer[26] = packetBuffer[42]; + packetBuffer[27] = packetBuffer[43]; + packetBuffer[28] = packetBuffer[44]; + packetBuffer[29] = packetBuffer[45]; + packetBuffer[30] = packetBuffer[46]; + packetBuffer[31] = packetBuffer[47]; + + // receive timestamp + packetBuffer[32] = (tempval >> 24) & 0XFF; + tempval = timestamp; + packetBuffer[33] = (tempval >> 16) & 0xFF; + tempval = timestamp; + packetBuffer[34] = (tempval >> 8) & 0xFF; + tempval = timestamp; + packetBuffer[35] = (tempval)&0xFF; + + packetBuffer[36] = 0; + packetBuffer[37] = 0; + packetBuffer[38] = 0; + packetBuffer[39] = 0; + + // transmitt timestamp + packetBuffer[40] = (tempval >> 24) & 0XFF; + tempval = timestamp; + packetBuffer[41] = (tempval >> 16) & 0xFF; + tempval = timestamp; + packetBuffer[42] = (tempval >> 8) & 0xFF; + tempval = timestamp; + packetBuffer[43] = (tempval)&0xFF; + + packetBuffer[44] = 0; + packetBuffer[45] = 0; + packetBuffer[46] = 0; + packetBuffer[47] = 0; + + // Reply to the IP address and port that sent the NTP request + + Udp.beginPacket(Remote, PortNum); + Udp.write(packetBuffer, NTP_PACKET_SIZE); + Udp.endPacket(); + + // syslog.logf(LOG_INFO, "NTP request from %s", Remote.toString().c_str()); + } +#if defined(ESP32) + vTaskDelay(1); + // taskYIELD(); +} +#endif +} + +void setup() +{ + DEBUG_PRINTLN(F("Starting setup...")); + pinMode(LOCK_LED, OUTPUT); + pinMode(PPS_LED, OUTPUT); + pinMode(WIFI_LED, OUTPUT); + pinMode(WIFI_BUTTON, INPUT_PULLUP); + + digitalWrite(LOCK_LED, LOW); + digitalWrite(PPS_LED, LOW); + digitalWrite(WIFI_LED, LOW); + + // if you are using ESP-01 then uncomment the line below to reset the pins to + // the available pins for SDA, SCL + DEBUG_PRINTLN(F("Starting LittleFS")); +#if defined(ARDUINO_ARCH_ESP8266) + // ss.begin (13U, 15U); // ESP8266 D7, D8 + ss.begin(9600); // set GPS baud rate to 9600 bps + Wire.begin(4U, 5U); // ESP8266 D2, D1 - due to limited pins, use pin 0 and 2 for SDA, SCL + LittleFS.begin(); // Init storage for WiFi SSID/PSK -- true = FORMAT_LITTLEFS_IF_FAILED +#elif defined(ESP32) + ss.begin(115200); + Wire.begin(21U, 22U); + LittleFS.begin(true); // Init storage for WiFi SSID/PSK -- true = FORMAT_LITTLEFS_IF_FAILED +#else +#error Unknown architecture +#endif + + Rtc.Begin(); + RtcEeprom.Begin(); + + InitLCD(); // initialize LCD display + +#ifdef DEBUG + Serial.begin(115200); // set serial monitor rate to 9600 bps +#endif + + // Serial.begin(9600); + delay(2000); + + syslogserver = readData("/syslogserver"); // Password follows + syslogserver.trim(); + + IPAddress ip; + ip.fromString(syslogserver); + // Syslog syslog(udpClient, syslogserver, SYSLOG_PORT, HOSTNAME, "esp-ntp", LOG_DAEMON); + syslog.server(ip, SYSLOG_PORT); + syslog.deviceHostname(HOSTNAME); + syslog.appName("esp-ntp"); + syslog.defaultPriority(LOG_DAEMON); + + DEBUG_PRINTLN("Iniciado"); + // DEBUG_PRINTLN(F(xPortGetCoreID())); + + // Initialize RTC + while (!Rtc.GetIsRunning()) + { + Rtc.SetIsRunning(true); + DEBUG_PRINTLN(F("RTC had to be force started")); + syslog.log(LOG_WARNING, "RTC had to be force started"); + } + + DEBUG_PRINTLN(F("RTC started")); + + // never assume the Rtc was last configured by you, so + // just clear them to your needed state + Rtc.Enable32kHzPin(false); + Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone); + +#ifdef DEBUG + PrintRTCstatus(); // show RTC diagnostics +#endif + SyncWithRTC(); // start clock with RTC data + attachInterrupt(PPS_PIN, isr, RISING); // enable GPS 1pps interrupt input + attachInterrupt(WIFI_BUTTON, btw, CHANGE); + + processWifi(); + + // Startup UDP + Udp.begin(NTP_PORT); + RFC868server.begin(); + +#if defined(ARDUINO_ARCH_ESP8266) +#elif defined(ESP32) + // xTaskCreatePinnedToCore( + // Task1code, /* Function to implement the task */ + //"Task1", /* Name of the task */ + // 10000, /* Stack size in words */ + // NULL, /* Task input parameter */ + // 0, /* Priority of the task */ + //&Task1, /* Task handle. */ + // 0); /* Core where the task should run */ + xTaskCreate(FeedGpsParser, "FeedGpsParser", 2048, NULL, 1, NULL); // decode incoming GPS data + xTaskCreate(SyncCheck, "SyncCheck", 2048, NULL, 1, NULL); // synchronize to GPS or RTC + xTaskCreate(processNTP, "processNTP", 2048, NULL, 1, NULL); + xTaskCreate(processRFC868, "processRFC868", 2048, NULL, 1, NULL); +#else +#error Unknown architecture +#endif +} + +//////////////////////////////////////// + +void loop() +{ +#if defined(ARDUINO_ARCH_ESP8266) + FeedGpsParser(); // decode incoming GPS data + SyncCheck(); // synchronize to GPS or RTC + processNTP(); + processRFC868(); +#elif defined(ESP32) +#else +#error Unknown architecture +#endif + + UpdateDisplay(); // if time has changed, display it + server.handleClient(); + if (millis() - pps_blink_time > PPS_BLINK_INTERVAL) // If x milliseconds passed, then it's time to switch led off for blink effect + digitalWrite(PPS_LED, LOW); + if (buttonPressed) + { // Process keycheck of button presses outside ISR to avoid crash + buttonPressed = false; + KeyCheck(); + } +} diff --git a/src/platformio.ini b/src/platformio.ini index a460340..e088b2c 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -8,6 +8,21 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html +[env:ESP32Duino] +board = esp32doit-espduino +board_build.f_cpu = 240000000L +platform = espressif32 +framework = arduino +upload_speed = 921600 +monitor_speed = 115200 +board_build.filesystem = littlefs +lib_deps = + paulstoffregen/Time@^1.6 + makuna/RTC@^2.3.5 + olikraus/U8g2@^2.28.8 + arcao/Syslog@^2.0.0 + mikalhart/TinyGPSPlus@^1.0.3 + [env:Amica] platform = espressif8266 upload_speed = 115200