Merge pull request #1997 from Aircoookie/toki

More precise NTP timekeeping
This commit is contained in:
Christian Schwinne 2021-05-30 13:27:35 +02:00 committed by GitHub
commit 7019ddb165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1372 additions and 1294 deletions

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x17B000,
app1, app, ota_1, 0x18B000,0x17B000,
spiffs, data, spiffs, 0x306000,0x0FA000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x17B000
5 app1 app ota_1 0x18B000 0x17B000
6 spiffs data spiffs 0x306000 0x0FA000

View File

@ -1,6 +1,7 @@
#ifndef TFTS_H #ifndef TFTS_H
#define TFTS_H #define TFTS_H
#include "wled.h"
#include <FS.h> #include <FS.h>
#include <TFT_eSPI.h> #include <TFT_eSPI.h>
@ -92,9 +93,10 @@ private:
uint16_t padding = (4 - ((w * 3) & 3)) & 3; uint16_t padding = (4 - ((w * 3) & 3)) & 3;
uint8_t lineBuffer[w * 3 + padding]; uint8_t lineBuffer[w * 3 + padding];
uint8_t serviceStrip = (!realtimeMode || realtimeOverride) ? 7 : 0;
// row is decremented as the BMP image is drawn bottom up // row is decremented as the BMP image is drawn bottom up
for (row = h-1; row >= 0; row--) { for (row = h-1; row >= 0; row--) {
if (row & 0b00000111 == 7) strip.service(); //still refresh backlight to mitigate stutter every few rows if ((row & 0b00000111) == serviceStrip) strip.service(); //still refresh backlight to mitigate stutter every few rows
bmpFS.read(lineBuffer, sizeof(lineBuffer)); bmpFS.read(lineBuffer, sizeof(lineBuffer));
uint8_t* bptr = lineBuffer; uint8_t* bptr = lineBuffer;

View File

@ -40,19 +40,16 @@ class ElekstubeIPSUsermod : public Usermod {
void setup() { void setup() {
tfts.begin(); tfts.begin();
tfts.fillScreen(TFT_BLACK); tfts.fillScreen(TFT_BLACK);
tfts.setTextColor(TFT_WHITE, TFT_BLACK);
tfts.setCursor(0, 0, 2); for (int8_t i = 5; i >= 0; i--) {
tfts.println("<STARTUP>"); tfts.setDigit(i, 255, TFTs::force); //turn all off
}
} }
void loop() { void loop() {
if (lastTime == 0) { if (toki.isTick()) {
tfts.fillScreen(TFT_BLACK); updateLocalTime();
updateClockDisplay(TFTs::force);
}
if (millis() - lastTime > 100) {
updateClockDisplay(); updateClockDisplay();
lastTime = millis();
} }
} }

View File

@ -14,7 +14,7 @@ class RTCUsermod : public Usermod {
void setup() { void setup() {
time_t rtcTime = RTC.get(); time_t rtcTime = RTC.get();
if (rtcTime) { if (rtcTime) {
setTime(rtcTime); toki.setTime(rtcTime,TOKI_NO_MS_ACCURACY,TOKI_TS_RTC);
updateLocalTime(); updateLocalTime();
} else { } else {
if (!RTC.chipPresent()) disabled = true; //don't waste time if H/W error if (!RTC.chipPresent()) disabled = true; //don't waste time if H/W error
@ -22,11 +22,9 @@ class RTCUsermod : public Usermod {
} }
void loop() { void loop() {
if (!disabled && millis() - lastTime > 500) { if (!disabled && toki.isTick()) {
time_t t = now(); time_t t = toki.second();
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
lastTime = millis();
} }
} }

View File

@ -85,7 +85,7 @@ public:
if (m_pD2D && (999000000L != ntpLastSyncTime)) if (m_pD2D && (999000000L != ntpLastSyncTime))
{ {
// to prevent needing to import all the timezone stuff from other modules, work completely in UTC // to prevent needing to import all the timezone stuff from other modules, work completely in UTC
time_t timeUTC = now(); time_t timeUTC = toki.second();
tmElements_t tmNow; tmElements_t tmNow;
breakTime(timeUTC, tmNow); breakTime(timeUTC, tmNow);
int nCurMinute = tmNow.Minute; int nCurMinute = tmNow.Minute;

View File

@ -42,30 +42,24 @@ uint16_t WS2812FX::mode_static(void) {
* Blink/strobe function * Blink/strobe function
* Alternate between color1 and color2 * Alternate between color1 and color2
* if(strobe == true) then create a strobe effect * if(strobe == true) then create a strobe effect
* NOTE: Maybe re-rework without timer
*/ */
uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) { uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) {
uint16_t stateTime = SEGENV.aux1;
uint32_t cycleTime = (255 - SEGMENT.speed)*20; uint32_t cycleTime = (255 - SEGMENT.speed)*20;
uint32_t onTime = 0; uint32_t onTime = FRAMETIME;
uint32_t offTime = cycleTime; if (!strobe) onTime += ((cycleTime * SEGMENT.intensity) >> 8);
cycleTime += FRAMETIME*2;
if (!strobe) { uint32_t it = now / cycleTime;
onTime = (cycleTime * SEGMENT.intensity) >> 8; uint32_t rem = now % cycleTime;
offTime = cycleTime - onTime;
bool on = false;
if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief
|| rem <= onTime) {
on = true;
} }
stateTime = ((SEGENV.aux0 & 1) == 0) ? onTime : offTime; SEGENV.step = it; //save previous iteration
stateTime += 20;
if (now - SEGENV.step > stateTime)
{
SEGENV.aux0++;
SEGENV.aux1 = stateTime;
SEGENV.step = now;
}
uint32_t color = ((SEGENV.aux0 & 1) == 0) ? color1 : color2; uint32_t color = on ? color1 : color2;
if (color == color1 && do_palette) if (color == color1 && do_palette)
{ {
for(uint16_t i = 0; i < SEGLEN; i++) { for(uint16_t i = 0; i < SEGLEN; i++) {

View File

@ -75,7 +75,7 @@
#define SEGENV _segment_runtimes[_segment_index] #define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN _virtualSegmentLength #define SEGLEN _virtualSegmentLength
#define SEGACT SEGMENT.stop #define SEGACT SEGMENT.stop
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGLEN #define SPEED_FORMULA_L 5U + (50U*(255U - SEGMENT.speed))/SEGLEN
#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes)) #define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes))
// some common colors // some common colors

View File

@ -1036,7 +1036,10 @@ function requestJson(command, rinfo = true, verbose = true) {
d.getElementById('sliderIntensity').value = i.ix; d.getElementById('sliderIntensity').value = i.ix;
// Effects // Effects
e1.querySelector(`input[name="fx"][value="${i.fx}"]`).checked = true; var selFx = e1.querySelector(`input[name="fx"][value="${i.fx}"]`);
if (selFx) selFx.checked = true;
else location.reload(); //effect list is gone (e.g. if restoring tab). Reload.
var selElement = e1.querySelector('.selected'); var selElement = e1.querySelector('.selected');
if (selElement) { if (selElement) {
selElement.classList.remove('selected') selElement.classList.remove('selected')

View File

@ -127,6 +127,7 @@ bool initMqtt();
void publishMqtt(); void publishMqtt();
//ntp.cpp //ntp.cpp
void handleTime();
void handleNetworkTime(); void handleNetworkTime();
void sendNTPPacket(); void sendNTPPacket();
bool checkNTPResponse(); bool checkNTPResponse();
@ -137,6 +138,7 @@ void setCountdown();
byte weekdayMondayFirst(); byte weekdayMondayFirst();
void checkTimers(); void checkTimers();
void calculateSunriseAndSunset(); void calculateSunriseAndSunset();
void setTimeFromAPI(uint32_t timein);
//overlay.cpp //overlay.cpp
void initCronixie(); void initCronixie();

View File

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

View File

@ -210,14 +210,7 @@ bool deserializeState(JsonObject root)
unsigned long timein = root[F("time")] | UINT32_MAX; //backup time source if NTP not synced unsigned long timein = root[F("time")] | UINT32_MAX; //backup time source if NTP not synced
if (timein != UINT32_MAX) { if (timein != UINT32_MAX) {
time_t prev = now(); setTimeFromAPI(timein);
if (millis() - ntpLastSyncTime > 50000000L) {
setTime(timein);
if (abs(now() - prev) > 60L) {
updateLocalTime();
calculateSunriseAndSunset();
}
}
if (presetsModifiedTime == 0) presetsModifiedTime = timein; if (presetsModifiedTime == 0) presetsModifiedTime = timein;
} }

View File

@ -5,6 +5,9 @@
/* /*
* Acquires time from NTP server * Acquires time from NTP server
*/ */
//#define WLED_DEBUG_NTP
#define NTP_SYNC_INTERVAL 42000UL //Get fresh NTP time about twice per day
Timezone* tz; Timezone* tz;
#define TZ_UTC 0 #define TZ_UTC 0
@ -133,9 +136,28 @@ void updateTimezone() {
tz = new Timezone(tcrDaylight, tcrStandard); tz = new Timezone(tcrDaylight, tcrStandard);
} }
void handleTime() {
handleNetworkTime();
toki.millisecond();
toki.setTick();
if (toki.isTick()) //true only in the first loop after a new second started
{
#ifdef WLED_DEBUG_NTP
Serial.print(F("TICK! "));
toki.printTime(toki.getTime());
#endif
updateLocalTime();
checkTimers();
checkCountdown();
handleOverlays();
}
}
void handleNetworkTime() void handleNetworkTime()
{ {
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WLED_CONNECTED) if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > (1000*NTP_SYNC_INTERVAL) && WLED_CONNECTED)
{ {
if (millis() - ntpPacketSentTime > 10000) if (millis() - ntpPacketSentTime > 10000)
{ {
@ -182,35 +204,52 @@ void sendNTPPacket()
bool checkNTPResponse() bool checkNTPResponse()
{ {
int cb = ntpUdp.parsePacket(); int cb = ntpUdp.parsePacket();
if (cb) { if (!cb) return false;
DEBUG_PRINT(F("NTP recv, l="));
DEBUG_PRINTLN(cb);
byte pbuf[NTP_PACKET_SIZE];
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
unsigned long highWord = word(pbuf[40], pbuf[41]); uint32_t ntpPacketReceivedTime = millis();
unsigned long lowWord = word(pbuf[42], pbuf[43]); DEBUG_PRINT(F("NTP recv, l="));
if (highWord == 0 && lowWord == 0) return false; DEBUG_PRINTLN(cb);
byte pbuf[NTP_PACKET_SIZE];
unsigned long secsSince1900 = highWord << 16 | lowWord; ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
DEBUG_PRINT(F("Unix time = ")); Toki::Time arrived = toki.fromNTP(pbuf + 32);
unsigned long epoch = secsSince1900 - 2208988799UL; //subtract 70 years -1sec (on avg. more precision) Toki::Time departed = toki.fromNTP(pbuf + 40);
setTime(epoch); if (departed.sec == 0) return false;
DEBUG_PRINTLN(epoch); //basic half roundtrip estimation
if (countdownTime - now() > 0) countdownOverTriggered = false; uint32_t serverDelay = toki.msDifference(arrived, departed);
// if time changed re-calculate sunrise/sunset uint32_t offset = (ntpPacketReceivedTime - ntpPacketSentTime - serverDelay) >> 1;
updateLocalTime(); #ifdef WLED_DEBUG_NTP
calculateSunriseAndSunset(); //the time the packet departed the NTP server
return true; toki.printTime(departed);
} #endif
return false;
toki.adjust(departed, offset);
toki.setTime(departed, TOKI_TS_NTP);
#ifdef WLED_DEBUG_NTP
Serial.print("Arrived: ");
toki.printTime(arrived);
Serial.print("Time: ");
toki.printTime(departed);
Serial.print("Roundtrip: ");
Serial.println(ntpPacketReceivedTime - ntpPacketSentTime);
Serial.print("Offset: ");
Serial.println(offset);
Serial.print("Serverdelay: ");
Serial.println(serverDelay);
#endif
if (countdownTime - toki.second() > 0) countdownOverTriggered = false;
// if time changed re-calculate sunrise/sunset
updateLocalTime();
calculateSunriseAndSunset();
return true;
} }
void updateLocalTime() void updateLocalTime()
{ {
if (currentTimezone != tzCurrent) updateTimezone(); if (currentTimezone != tzCurrent) updateTimezone();
unsigned long tmc = now()+ utcOffsetSecs; unsigned long tmc = toki.second()+ utcOffsetSecs;
localTime = tz->toLocal(tmc); localTime = tz->toLocal(tmc);
} }
@ -234,13 +273,13 @@ void setCountdown()
{ {
if (currentTimezone != tzCurrent) updateTimezone(); if (currentTimezone != tzCurrent) updateTimezone();
countdownTime = tz->toUTC(getUnixTime(countdownHour, countdownMin, countdownSec, countdownDay, countdownMonth, countdownYear)); countdownTime = tz->toUTC(getUnixTime(countdownHour, countdownMin, countdownSec, countdownDay, countdownMonth, countdownYear));
if (countdownTime - now() > 0) countdownOverTriggered = false; if (countdownTime - toki.second() > 0) countdownOverTriggered = false;
} }
//returns true if countdown just over //returns true if countdown just over
bool checkCountdown() bool checkCountdown()
{ {
unsigned long n = now(); unsigned long n = toki.second();
if (countdownMode) localTime = countdownTime - n + utcOffsetSecs; if (countdownMode) localTime = countdownTime - n + utcOffsetSecs;
if (n > countdownTime) { if (n > countdownTime) {
if (countdownMode) localTime = n - countdownTime + utcOffsetSecs; if (countdownMode) localTime = n - countdownTime + utcOffsetSecs;
@ -399,3 +438,19 @@ void calculateSunriseAndSunset() {
} }
} }
} }
//time from JSON and HTTP API
void setTimeFromAPI(uint32_t timein) {
if (timein == 0 || timein == UINT32_MAX) return;
uint32_t prev = toki.second();
//only apply if more accurate or there is a significant difference to the "more accurate" time source
uint32_t diff = (timein > prev) ? timein - prev : prev - timein;
if (toki.getTimeSource() > TOKI_TS_JSON && diff < 60U) return;
toki.setTime(timein, TOKI_NO_MS_ACCURACY, TOKI_TS_JSON);
if (diff >= 60U) {
updateLocalTime();
calculateSunriseAndSunset();
}
if (presetsModifiedTime == 0) presetsModifiedTime = timein;
}

View File

@ -6,29 +6,24 @@
void initCronixie() void initCronixie()
{ {
if (overlayCurrent == 3 && !cronixieInit) if (overlayCurrent == 3 && dP[0] == 255) //if dP[0] is 255, cronixie is not yet init'ed
{ {
setCronixie(); setCronixie();
strip.getSegment(0).grouping = 10; //10 LEDs per digit strip.getSegment(0).grouping = 10; //10 LEDs per digit
cronixieInit = true; } else if (dP[0] < 255 && overlayCurrent != 3)
} else if (cronixieInit && overlayCurrent != 3)
{ {
strip.getSegment(0).grouping = 1; strip.getSegment(0).grouping = 1;
cronixieInit = false; dP[0] = 255;
} }
} }
void handleOverlays() void handleOverlays()
{ {
if (millis() - overlayRefreshedTime > overlayRefreshMs) initCronixie();
{ if (overlayCurrent == 3) {
initCronixie(); _overlayCronixie();//Diamex cronixie clock kit
updateLocalTime(); strip.trigger();
checkTimers();
checkCountdown();
if (overlayCurrent == 3) _overlayCronixie();//Diamex cronixie clock kit
overlayRefreshedTime = millis();
} }
} }
@ -73,15 +68,14 @@ void _overlayAnalogClock()
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000); if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000);
strip.setPixelColor(minutePixel, 0x00FF00); strip.setPixelColor(minutePixel, 0x00FF00);
strip.setPixelColor(hourPixel, 0x0000FF); strip.setPixelColor(hourPixel, 0x0000FF);
overlayRefreshMs = 998;
} }
void _overlayAnalogCountdown() void _overlayAnalogCountdown()
{ {
if ((unsigned long)now() < countdownTime) if ((unsigned long)toki.second() < countdownTime)
{ {
long diff = countdownTime - now(); long diff = countdownTime - toki.second();
double pval = 60; double pval = 60;
if (diff > 31557600L) //display in years if more than 365 days if (diff > 31557600L) //display in years if more than 365 days
{ {
@ -115,7 +109,6 @@ void _overlayAnalogCountdown()
strip.setRange(analogClock12pixel, analogClock12pixel + pixelCnt, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]); strip.setRange(analogClock12pixel, analogClock12pixel + pixelCnt, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
} }
} }
overlayRefreshMs = 998;
} }
@ -219,8 +212,6 @@ void setCronixie()
DEBUG_PRINT("cset "); DEBUG_PRINT("cset ");
DEBUG_PRINTLN(cronixieDisplay); DEBUG_PRINTLN(cronixieDisplay);
overlayRefreshMs = 1997; //Only refresh every 2secs if no seconds are displayed
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
@ -241,8 +232,8 @@ void setCronixie()
case 'a': dP[i] = 58; i++; break; case 'a': dP[i] = 58; i++; break;
case 'm': dP[i] = 74 + getSameCodeLength('m',i,cronixieDisplay); i = i+dP[i]-74; break; case 'm': dP[i] = 74 + getSameCodeLength('m',i,cronixieDisplay); i = i+dP[i]-74; break;
case 'M': dP[i] = 24 + getSameCodeLength('M',i,cronixieDisplay); i = i+dP[i]-24; break; case 'M': dP[i] = 24 + getSameCodeLength('M',i,cronixieDisplay); i = i+dP[i]-24; break;
case 's': dP[i] = 80 + getSameCodeLength('s',i,cronixieDisplay); i = i+dP[i]-80; overlayRefreshMs = 497; break; //refresh more often bc. of secs case 's': dP[i] = 80 + getSameCodeLength('s',i,cronixieDisplay); i = i+dP[i]-80; break; //refresh more often bc. of secs
case 'S': dP[i] = 30 + getSameCodeLength('S',i,cronixieDisplay); i = i+dP[i]-30; overlayRefreshMs = 497; break; case 'S': dP[i] = 30 + getSameCodeLength('S',i,cronixieDisplay); i = i+dP[i]-30; break;
case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,cronixieDisplay); i = i+dP[i]-36; break; case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,cronixieDisplay); i = i+dP[i]-36; break;
case 'y': dP[i] = 86 + getSameCodeLength('y',i,cronixieDisplay); i = i+dP[i]-86; break; case 'y': dP[i] = 86 + getSameCodeLength('y',i,cronixieDisplay); i = i+dP[i]-86; break;
case 'I': dP[i] = 39 + getSameCodeLength('I',i,cronixieDisplay); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M. case 'I': dP[i] = 39 + getSameCodeLength('I',i,cronixieDisplay); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M.

View File

@ -69,13 +69,13 @@ void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
writeObjectToFileUsingId("/presets.json", index, fileDoc); writeObjectToFileUsingId("/presets.json", index, fileDoc);
} }
presetsModifiedTime = now(); //unix time presetsModifiedTime = toki.second(); //unix time
updateFSInfo(); updateFSInfo();
} }
void deletePreset(byte index) { void deletePreset(byte index) {
StaticJsonDocument<24> empty; StaticJsonDocument<24> empty;
writeObjectToFileUsingId("/presets.json", index, &empty); writeObjectToFileUsingId("/presets.json", index, &empty);
presetsModifiedTime = now(); //unix time presetsModifiedTime = toki.second(); //unix time
updateFSInfo(); updateFSInfo();
} }

View File

@ -806,14 +806,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set time (unix timestamp) //set time (unix timestamp)
pos = req.indexOf(F("ST=")); pos = req.indexOf(F("ST="));
if (pos > 0) { if (pos > 0) {
setTime(getNumVal(&req, pos)); setTimeFromAPI(getNumVal(&req, pos));
} }
//set countdown goal (unix timestamp) //set countdown goal (unix timestamp)
pos = req.indexOf(F("CT=")); pos = req.indexOf(F("CT="));
if (pos > 0) { if (pos > 0) {
countdownTime = getNumVal(&req, pos); countdownTime = getNumVal(&req, pos);
if (countdownTime - now() > 0) countdownOverTriggered = false; if (countdownTime - toki.second() > 0) countdownOverTriggered = false;
} }
pos = req.indexOf(F("LO=")); pos = req.indexOf(F("LO="));
@ -841,7 +841,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (pos > 0) //sets backlight if (pos > 0) //sets backlight
{ {
cronixieBacklight = (req.charAt(pos+3) != '0'); cronixieBacklight = (req.charAt(pos+3) != '0');
overlayRefreshedTime = 0;
} }
#endif #endif

View File

@ -1,5 +1,9 @@
Readme file for Arduino Time Library Readme file for Arduino Time Library
! MODIFIED DISTRIBUTION FOR WLED
All timekeeping functions are removed, only conversion functions used.
Please see https://github.com/PaulStoffregen/Time for the full, original library
Time is a library that provides timekeeping functionality for Arduino. Time is a library that provides timekeeping functionality for Arduino.
The code is derived from the Playground DateTime library but is updated The code is derived from the Playground DateTime library but is updated
@ -14,26 +18,10 @@ for time synchronization.
The functions available in the library include: The functions available in the library include:
hour(); // the hour now (0-23) The time and date functions take a parameter for the time. This prevents
minute(); // the minute now (0-59)
second(); // the second now (0-59)
day(); // the day now (1-31)
weekday(); // day of the week (1-7), Sunday is day 1
month(); // the month now (1-12)
year(); // the full four digit year: (2009, 2010 etc)
there are also functions to return the hour in 12 hour format
hourFormat12(); // the hour now in 12 hour format
isAM(); // returns true if time now is AM
isPM(); // returns true if time now is PM
now(); // returns the current time as seconds since Jan 1 1970
The time and date functions can take an optional parameter for the time. This prevents
errors if the time rolls over between elements. For example, if a new minute begins errors if the time rolls over between elements. For example, if a new minute begins
between getting the minute and second, the values will be inconsistent. Using the between getting the minute and second, the values will be inconsistent. Using the
following functions eliminates this probglem following functions eliminates this problem
time_t t = now(); // store the current time in time variable t
hour(t); // returns the hour for the given time t hour(t); // returns the hour for the given time t
minute(t); // returns the minute for the given time t minute(t); // returns the minute for the given time t
second(t); // returns the second for the given time t second(t); // returns the second for the given time t
@ -43,25 +31,6 @@ following functions eliminates this probglem
year(t); // the year for the given time t year(t); // the year for the given time t
Functions for managing the timer services are:
setTime(t); // set the system time to the give time t
setTime(hr,min,sec,day,mnth,yr); // alternative to above, yr is 2 or 4 digit yr
// (2010 or 10 sets year to 2010)
adjustTime(adjustment); // adjust system time by adding the adjustment value
timeStatus(); // indicates if time has been set and recently synchronized
// returns one of the following enumerations:
timeNotSet // the time has never been set, the clock started at Jan 1 1970
timeNeedsSync // the time had been set but a sync attempt did not succeed
timeSet // the time is set and is synced
Time and Date values are not valid if the status is timeNotSet. Otherwise values can be used but
the returned time may have drifted if the status is timeNeedsSync.
setSyncProvider(getTimeFunction); // set the external time provider
setSyncInterval(interval); // set the number of seconds between re-sync
There are many convenience macros in the time.h file for time constants and conversion There are many convenience macros in the time.h file for time constants and conversion
of time units. of time units.

View File

@ -25,6 +25,7 @@
examples, add error checking and messages to RTC examples, examples, add error checking and messages to RTC examples,
add examples to DS1307RTC library. add examples to DS1307RTC library.
1.4 5 Sep 2014 - compatibility with Arduino 1.5.7 1.4 5 Sep 2014 - compatibility with Arduino 1.5.7
2.0 25 May 2021 - removed timing code, only used for conversion between unix and time
*/ */
#if ARDUINO >= 100 #if ARDUINO >= 100
@ -37,7 +38,6 @@
static tmElements_t tm; // a cache of time elements static tmElements_t tm; // a cache of time elements
static time_t cacheTime; // the time the cache was updated static time_t cacheTime; // the time the cache was updated
static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds
void refreshCache(time_t t) { void refreshCache(time_t t) {
if (t != cacheTime) { if (t != cacheTime) {
@ -46,19 +46,11 @@ void refreshCache(time_t t) {
} }
} }
int hour() { // the hour now
return hour(now());
}
int hour(time_t t) { // the hour for the given time int hour(time_t t) { // the hour for the given time
refreshCache(t); refreshCache(t);
return tm.Hour; return tm.Hour;
} }
int hourFormat12() { // the hour now in 12 hour format
return hourFormat12(now());
}
int hourFormat12(time_t t) { // the hour for the given time in 12 hour format int hourFormat12(time_t t) { // the hour for the given time in 12 hour format
refreshCache(t); refreshCache(t);
if( tm.Hour == 0 ) if( tm.Hour == 0 )
@ -69,71 +61,39 @@ int hourFormat12(time_t t) { // the hour for the given time in 12 hour format
return tm.Hour ; return tm.Hour ;
} }
uint8_t isAM() { // returns true if time now is AM
return !isPM(now());
}
uint8_t isAM(time_t t) { // returns true if given time is AM uint8_t isAM(time_t t) { // returns true if given time is AM
return !isPM(t); return !isPM(t);
} }
uint8_t isPM() { // returns true if PM
return isPM(now());
}
uint8_t isPM(time_t t) { // returns true if PM uint8_t isPM(time_t t) { // returns true if PM
return (hour(t) >= 12); return (hour(t) >= 12);
} }
int minute() {
return minute(now());
}
int minute(time_t t) { // the minute for the given time int minute(time_t t) { // the minute for the given time
refreshCache(t); refreshCache(t);
return tm.Minute; return tm.Minute;
} }
int second() {
return second(now());
}
int second(time_t t) { // the second for the given time int second(time_t t) { // the second for the given time
refreshCache(t); refreshCache(t);
return tm.Second; return tm.Second;
} }
int day(){
return(day(now()));
}
int day(time_t t) { // the day for the given time (0-6) int day(time_t t) { // the day for the given time (0-6)
refreshCache(t); refreshCache(t);
return tm.Day; return tm.Day;
} }
int weekday() { // Sunday is day 1
return weekday(now());
}
int weekday(time_t t) { int weekday(time_t t) {
refreshCache(t); refreshCache(t);
return tm.Wday; return tm.Wday;
} }
int month(){
return month(now());
}
int month(time_t t) { // the month for the given time int month(time_t t) { // the month for the given time
refreshCache(t); refreshCache(t);
return tm.Month; return tm.Month;
} }
int year() { // as in Processing, the full four digit year: (2009, 2010 etc)
return year(now());
}
int year(time_t t) { // the year for the given time int year(time_t t) { // the year for the given time
refreshCache(t); refreshCache(t);
return tmYearToCalendar(tm.Year); return tmYearToCalendar(tm.Year);
@ -231,57 +191,6 @@ time_t makeTime(tmElements_t &tm){
seconds+= tm.Second; seconds+= tm.Second;
return (time_t)seconds; return (time_t)seconds;
} }
/*=====================================================*/
/* Low level system time functions */
static uint32_t sysTime = 0;
static uint32_t prevMillis = 0;
static uint32_t nextSyncTime = 0;
static timeStatus_t Status = timeNotSet;
getExternalTime getTimePtr; // pointer to external sync function
//setExternalTime setTimePtr; // not used in this version
#ifdef TIME_DRIFT_INFO // define this to get drift data
time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync
#endif
time_t now() {
// calculate number of seconds passed since last call to now()
while (millis() - prevMillis >= 1000) {
// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
sysTime++;
prevMillis += 1000;
#ifdef TIME_DRIFT_INFO
sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift
#endif
}
if (nextSyncTime <= sysTime) {
if (getTimePtr != 0) {
time_t t = getTimePtr();
if (t != 0) {
setTime(t);
} else {
nextSyncTime = sysTime + syncInterval;
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
}
}
}
return (time_t)sysTime;
}
void setTime(time_t t) {
#ifdef TIME_DRIFT_INFO
if(sysUnsyncedTime == 0)
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
#endif
sysTime = (uint32_t)t;
nextSyncTime = (uint32_t)t + syncInterval;
Status = timeSet;
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
}
time_t getUnixTime(int hr,int min,int sec,int dy, int mnth, int yr){ time_t getUnixTime(int hr,int min,int sec,int dy, int mnth, int yr){
// year can be given as full four digit year or two digts (2010 or 10 for 2010); // year can be given as full four digit year or two digts (2010 or 10 for 2010);
@ -297,29 +206,4 @@ time_t getUnixTime(int hr,int min,int sec,int dy, int mnth, int yr){
tm.Minute = min; tm.Minute = min;
tm.Second = sec; tm.Second = sec;
return makeTime(tm); return makeTime(tm);
} }
void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
setTime(getUnixTime(hr,min,sec,dy,mnth,yr));
}
void adjustTime(long adjustment) {
sysTime += adjustment;
}
// indicates if time has been set and recently synchronized
timeStatus_t timeStatus() {
now(); // required to actually update the status
return Status;
}
void setSyncProvider( getExternalTime getTimeFunction){
getTimePtr = getTimeFunction;
nextSyncTime = sysTime;
now(); // this will sync the clock
}
void setSyncInterval(time_t interval){ // set the number of seconds between re-sync
syncInterval = (uint32_t)interval;
nextSyncTime = sysTime + syncInterval;
}

View File

@ -31,8 +31,6 @@ typedef unsigned long time_t;
// but at least this hack lets us define C++ functions as intended. Hopefully // but at least this hack lets us define C++ functions as intended. Hopefully
// nothing too terrible will result from overriding the C library header?! // nothing too terrible will result from overriding the C library header?!
extern "C++" { extern "C++" {
typedef enum {timeNotSet, timeNeedsSync, timeSet
} timeStatus_t ;
typedef enum { typedef enum {
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
@ -95,33 +93,19 @@ typedef time_t(*getExternalTime)();
#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) #define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK)
/*============================================================================*/ /*============================================================================*/
/* time and date functions */ /* time and date functions */
int hour(); // the hour now
int hour(time_t t); // the hour for the given time int hour(time_t t); // the hour for the given time
int hourFormat12(); // the hour now in 12 hour format
int hourFormat12(time_t t); // the hour for the given time in 12 hour format int hourFormat12(time_t t); // the hour for the given time in 12 hour format
uint8_t isAM(); // returns true if time now is AM
uint8_t isAM(time_t t); // returns true the given time is AM uint8_t isAM(time_t t); // returns true the given time is AM
uint8_t isPM(); // returns true if time now is PM
uint8_t isPM(time_t t); // returns true the given time is PM uint8_t isPM(time_t t); // returns true the given time is PM
int minute(); // the minute now
int minute(time_t t); // the minute for the given time int minute(time_t t); // the minute for the given time
int second(); // the second now
int second(time_t t); // the second for the given time int second(time_t t); // the second for the given time
int day(); // the day now
int day(time_t t); // the day for the given time int day(time_t t); // the day for the given time
int weekday(); // the weekday now (Sunday is day 1)
int weekday(time_t t); // the weekday for the given time int weekday(time_t t); // the weekday for the given time
int month(); // the month now (Jan is month 1)
int month(time_t t); // the month for the given time int month(time_t t); // the month for the given time
int year(); // the full four digit year: (2009, 2010 etc)
int year(time_t t); // the year for the given time int year(time_t t); // the year for the given time
time_t now(); // return the current time as seconds since Jan 1 1970
void setTime(time_t t);
void setTime(int hr,int min,int sec,int day, int month, int yr);
time_t getUnixTime(int hr,int min,int sec,int day, int month, int yr); //added by Aircoookie to get epoch time time_t getUnixTime(int hr,int min,int sec,int day, int month, int yr); //added by Aircoookie to get epoch time
void adjustTime(long adjustment);
/* date strings */ /* date strings */
#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null) #define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null)
@ -129,13 +113,8 @@ char* monthStr(uint8_t month);
char* dayStr(uint8_t day); char* dayStr(uint8_t day);
char* monthShortStr(uint8_t month); char* monthShortStr(uint8_t month);
char* dayShortStr(uint8_t day); char* dayShortStr(uint8_t day);
/* time sync functions */
timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized
void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider
void setSyncInterval(time_t interval); // set the number of seconds between re-sync
/* low level functions to convert to and from system time */ /* low level functions to convert to and from system time */
void breakTime(time_t time, tmElements_t &tm); // break time_t into elements void breakTime(time_t time, tmElements_t &tm); // break time_t into elements
time_t makeTime(tmElements_t &tm); // convert time elements into time_t time_t makeTime(tmElements_t &tm); // convert time elements into time_t

View File

@ -0,0 +1,161 @@
/*
Toki.h - Minimal millisecond accurate timekeeping.
LICENSE
The MIT License (MIT)
Copyright (c) 2021 Christian Schwinne
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <Arduino.h>
#define YEARS_70 2208988800UL
#define TOKI_NO_MS_ACCURACY 1000
//Time source. Sub-100 is second accuracy, higher ms accuracy. Higher value generally means more accurate
#define TOKI_TS_NONE 0 //unsynced (e.g. just after boot)
#define TOKI_TS_UDP 5 //synced via UDP from an instance whose time source is unsynced
#define TOKI_TS_BAD 10 //synced from a time source less than about +- 2s accurate
#define TOKI_TS_UDP_SEC 20 //synced via UDP from an instance whose time source is set from RTC/JSON
#define TOKI_TS_SEC 40 //general second-accurate time source
#define TOKI_TS_RTC 60 //second-accurate real time clock
#define TOKI_TS_JSON 70 //synced second-accurate from a client via JSON-API
#define TOKI_TS_UDP_NTP 110 //synced via UDP from an instance whose time source is NTP
#define TOKI_TS_MS 120 //general better-than-second accuracy time source
#define TOKI_TS_NTP 150 //NTP time, simple round trip estimation. Depending on network, mostly +- 50ms accurate
#define TOKI_TS_NTP_P 170 //NTP time with multi-step sync, higher accuracy. Not implemented in WLED
class Toki {
typedef enum {
inactive, marked, active
} TickT;
public:
typedef struct {
uint32_t sec;
uint16_t ms;
} Time;
private:
uint32_t fullSecondMillis = 0;
uint32_t unix = 0;
TickT tick = TickT::inactive;
uint8_t timeSrc = TOKI_TS_NONE;
public:
void setTime(Time t, uint8_t timeSource = TOKI_TS_MS) {
fullSecondMillis = millis() - t.ms;
unix = t.sec;
timeSrc = timeSource;
}
void setTime(uint32_t sec, uint16_t ms=TOKI_NO_MS_ACCURACY, uint8_t timeSource = TOKI_TS_MS) {
if (ms >= TOKI_NO_MS_ACCURACY) {
ms = millisecond(); //just keep current ms if not provided
if (timeSource > 99) timeSource = TOKI_TS_SEC; //lies
}
Time t = {sec, ms};
setTime(t, timeSource);
}
Time fromNTP(byte *timestamp) { //ntp timestamp is 8 bytes, 4 bytes second and 4 bytes sub-second fraction
unsigned long highWord = word(timestamp[0], timestamp[1]);
unsigned long lowWord = word(timestamp[2], timestamp[3]);
unsigned long unix = highWord << 16 | lowWord;
if (!unix) return {0,0};
unix -= YEARS_70; //NTP begins 1900, Unix 1970
unsigned long frac = word(timestamp[4], timestamp[5]); //65536ths of a second
frac = (frac*1000) >> 16; //convert to ms
return {unix, (uint16_t)frac};
}
uint16_t millisecond() {
uint32_t ms = millis() - fullSecondMillis;
while (ms > 999) {
ms -= 1000;
fullSecondMillis += 1000;
unix++;
if (tick == TickT::inactive) tick = TickT::marked; //marked, will be active on next loop
}
return ms;
}
uint32_t second() {
millisecond();
return unix;
}
//gets the absolute difference between two timestamps in milliseconds
uint32_t msDifference(const Time &t0, const Time &t1) {
bool t1BiggerSec = (t1.sec > t0.sec);
uint32_t secDiff = (t1BiggerSec) ? t1.sec - t0.sec : t0.sec - t1.sec;
uint32_t t0ms = t0.ms, t1ms = t1.ms;
if (t1BiggerSec) t1ms += secDiff*1000;
else t0ms += secDiff*1000;
uint32_t msDiff = (t1ms > t0ms) ? t1ms - t0ms : t0ms - t1ms;
return msDiff;
}
//return true if t1 is later than t0
bool isLater(const Time &t0, const Time &t1) {
if (t1.sec > t0.sec) return true;
if (t1.sec < t0.sec) return false;
if (t1.ms > t0.ms) return true;
return false;
}
void adjust(Time&t, int32_t offset) {
int32_t secs = offset /1000;
int32_t ms = offset - secs*1000;
t.sec += secs;
int32_t nms = t.ms + ms;
if (nms > 1000) {nms -= 1000; t.sec++;}
if (nms < 0) {nms += 1000; t.sec--;}
t.ms = nms;
}
Time getTime() {
Time t;
t.ms = millisecond();
t.sec = unix;
return t;
}
uint8_t getTimeSource() {
return timeSrc;
}
void setTick() {
if (tick == TickT::marked) tick = TickT::active;
}
void resetTick() {
if (tick == TickT::active) tick = TickT::inactive;
}
bool isTick() {
return (tick == TickT::active);
}
void printTime(const Time& t) {
Serial.printf_P(PSTR("%u,%03u\n"),t.sec,t.ms);
}
};

View File

@ -4,8 +4,9 @@
* UDP sync notifier / Realtime / Hyperion / TPM2.NET * UDP sync notifier / Realtime / Hyperion / TPM2.NET
*/ */
#define WLEDPACKETSIZE 29 #define WLEDPACKETSIZE 36
#define UDP_IN_MAXSIZE 1472 #define UDP_IN_MAXSIZE 1472
#define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times
void notify(byte callMode, bool followUp) void notify(byte callMode, bool followUp)
{ {
@ -37,8 +38,8 @@ void notify(byte callMode, bool followUp)
//compatibilityVersionByte: //compatibilityVersionByte:
//0: old 1: supports white 2: supports secondary color //0: old 1: supports white 2: supports secondary color
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette //3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color //6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet
udpOut[11] = 7; udpOut[11] = 8;
udpOut[12] = colSec[0]; udpOut[12] = colSec[0];
udpOut[13] = colSec[1]; udpOut[13] = colSec[1];
udpOut[14] = colSec[2]; udpOut[14] = colSec[2];
@ -59,6 +60,18 @@ void notify(byte callMode, bool followUp)
udpOut[26] = (t >> 16) & 0xFF; udpOut[26] = (t >> 16) & 0xFF;
udpOut[27] = (t >> 8) & 0xFF; udpOut[27] = (t >> 8) & 0xFF;
udpOut[28] = (t >> 0) & 0xFF; udpOut[28] = (t >> 0) & 0xFF;
//sync system time
udpOut[29] = toki.getTimeSource();
Toki::Time tm = toki.getTime();
uint32_t unix = tm.sec;
udpOut[30] = (unix >> 24) & 0xFF;
udpOut[31] = (unix >> 16) & 0xFF;
udpOut[32] = (unix >> 8) & 0xFF;
udpOut[33] = (unix >> 0) & 0xFF;
uint16_t ms = tm.ms;
udpOut[34] = (ms >> 8) & 0xFF;
udpOut[35] = (ms >> 0) & 0xFF;
IPAddress broadcastIp; IPAddress broadcastIp;
broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP()); broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP());
@ -204,6 +217,9 @@ void handleNotifications()
//ignore notification if received within a second after sending a notification ourselves //ignore notification if received within a second after sending a notification ourselves
if (millis() - notificationSentTime < 1000) return; if (millis() - notificationSentTime < 1000) return;
if (udpIn[1] > 199) return; //do not receive custom versions if (udpIn[1] > 199) return; //do not receive custom versions
//compatibilityVersionByte:
byte version = udpIn[11];
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
//apply colors from notification //apply colors from notification
@ -212,40 +228,66 @@ void handleNotifications()
col[0] = udpIn[3]; col[0] = udpIn[3];
col[1] = udpIn[4]; col[1] = udpIn[4];
col[2] = udpIn[5]; col[2] = udpIn[5];
if (udpIn[11] > 0) //sending module's white val is intended if (version > 0) //sending module's white val is intended
{ {
col[3] = udpIn[10]; col[3] = udpIn[10];
if (udpIn[11] > 1) if (version > 1)
{ {
colSec[0] = udpIn[12]; colSec[0] = udpIn[12];
colSec[1] = udpIn[13]; colSec[1] = udpIn[13];
colSec[2] = udpIn[14]; colSec[2] = udpIn[14];
colSec[3] = udpIn[15]; colSec[3] = udpIn[15];
} }
if (udpIn[11] > 5) if (version > 6)
{
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
t += 2;
t -= millis();
strip.timebase = t;
}
if (udpIn[11] > 6)
{ {
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
} }
} }
} }
bool timebaseUpdated = false;
//apply effects from notification //apply effects from notification
if (udpIn[11] < 200 && (receiveNotificationEffects || !someSel)) if (version < 200 && (receiveNotificationEffects || !someSel))
{ {
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8]; if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
effectSpeed = udpIn[9]; effectSpeed = udpIn[9];
if (udpIn[11] > 2) effectIntensity = udpIn[16]; if (version > 2) effectIntensity = udpIn[16];
if (udpIn[11] > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19]; if (version > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
if (version > 5)
{
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
t += PRESUMED_NETWORK_DELAY; //adjust trivially for network delay
t -= millis();
strip.timebase = t;
timebaseUpdated = true;
}
}
//adjust system time, but only if sender is more accurate than self
if (version > 7)
{
Toki::Time tm;
tm.sec = (udpIn[30] << 24) | (udpIn[31] << 16) | (udpIn[32] << 8) | (udpIn[33]);
tm.ms = (udpIn[34] << 8) | (udpIn[35]);
if (udpIn[29] > toki.getTimeSource()) { //if sender's time source is more accurate
toki.adjust(tm, PRESUMED_NETWORK_DELAY); //adjust trivially for network delay
uint8_t ts = TOKI_TS_UDP;
if (udpIn[29] > 99) ts = TOKI_TS_UDP_NTP;
else if (udpIn[29] >= TOKI_TS_SEC) ts = TOKI_TS_UDP_SEC;
toki.setTime(tm, ts);
} else if (timebaseUpdated && toki.getTimeSource() > 99) { //if we both have good times, get a more accurate timebase
Toki::Time myTime = toki.getTime();
uint32_t diff = toki.msDifference(tm, myTime);
strip.timebase -= PRESUMED_NETWORK_DELAY; //no need to presume, use difference between NTP times at send and receive points
if (toki.isLater(tm, myTime)) {
strip.timebase += diff;
} else {
strip.timebase -= diff;
}
}
} }
if (udpIn[11] > 3) if (version > 3)
{ {
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00); transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
} }

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,7 @@
#include <SPIFFSEditor.h> #include <SPIFFSEditor.h>
#include "src/dependencies/time/TimeLib.h" #include "src/dependencies/time/TimeLib.h"
#include "src/dependencies/timezone/Timezone.h" #include "src/dependencies/timezone/Timezone.h"
#include "src/dependencies/toki/Toki.h"
#ifndef WLED_DISABLE_ALEXA #ifndef WLED_DISABLE_ALEXA
#define ESPALEXA_ASYNC #define ESPALEXA_ASYNC
@ -354,7 +355,7 @@ WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format
WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino
WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation
WLED_GLOBAL byte overlayDefault _INIT(0); // 0: no overlay 1: analog clock 2: single-digit clocl 3: cronixie WLED_GLOBAL byte overlayDefault _INIT(0); // 0: no overlay 1: analog clock 2: single-digit clock 3: cronixie
WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(ledCount - 1); // boundaries of overlay mode WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(ledCount - 1); // boundaries of overlay mode
WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be
@ -476,13 +477,9 @@ WLED_GLOBAL bool hueStoreAllowed _INIT(false), hueNewKey _INIT(false);
// overlays // overlays
WLED_GLOBAL byte overlayCurrent _INIT(overlayDefault); WLED_GLOBAL byte overlayCurrent _INIT(overlayDefault);
WLED_GLOBAL byte overlaySpeed _INIT(200);
WLED_GLOBAL unsigned long overlayRefreshMs _INIT(200);
WLED_GLOBAL unsigned long overlayRefreshedTime;
// cronixie // cronixie
WLED_GLOBAL byte dP[] _INIT_N(({ 0, 0, 0, 0, 0, 0 })); WLED_GLOBAL byte dP[] _INIT_N(({ 255, 255, 255, 255, 255, 255 }));
WLED_GLOBAL bool cronixieInit _INIT(false);
// countdown // countdown
WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L); WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L);
@ -545,6 +542,7 @@ WLED_GLOBAL float longitude _INIT(0.0);
WLED_GLOBAL float latitude _INIT(0.0); WLED_GLOBAL float latitude _INIT(0.0);
WLED_GLOBAL time_t sunrise _INIT(0); WLED_GLOBAL time_t sunrise _INIT(0);
WLED_GLOBAL time_t sunset _INIT(0); WLED_GLOBAL time_t sunset _INIT(0);
WLED_GLOBAL Toki toki _INIT(Toki());
// Temp buffer // Temp buffer
WLED_GLOBAL char* obuf; WLED_GLOBAL char* obuf;

View File

@ -224,7 +224,10 @@ void initServer()
//make API CORS compatible //make API CORS compatible
if (request->method() == HTTP_OPTIONS) if (request->method() == HTTP_OPTIONS)
{ {
request->send(200); return; AsyncWebServerResponse *response = request->beginResponse(200);
response->addHeader(F("Access-Control-Max-Age"), F("7200"));
request->send(response);
return;
} }
if(handleSet(request, request->url())) return; if(handleSet(request, request->url())) return;