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
#define TFTS_H
#include "wled.h"
#include <FS.h>
#include <TFT_eSPI.h>
@ -92,9 +93,10 @@ private:
uint16_t padding = (4 - ((w * 3) & 3)) & 3;
uint8_t lineBuffer[w * 3 + padding];
uint8_t serviceStrip = (!realtimeMode || realtimeOverride) ? 7 : 0;
// row is decremented as the BMP image is drawn bottom up
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));
uint8_t* bptr = lineBuffer;

View File

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

View File

@ -14,7 +14,7 @@ class RTCUsermod : public Usermod {
void setup() {
time_t rtcTime = RTC.get();
if (rtcTime) {
setTime(rtcTime);
toki.setTime(rtcTime,TOKI_NO_MS_ACCURACY,TOKI_TS_RTC);
updateLocalTime();
} else {
if (!RTC.chipPresent()) disabled = true; //don't waste time if H/W error
@ -22,11 +22,9 @@ class RTCUsermod : public Usermod {
}
void loop() {
if (!disabled && millis() - lastTime > 500) {
time_t t = now();
if (!disabled && toki.isTick()) {
time_t t = toki.second();
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))
{
// 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;
breakTime(timeUTC, tmNow);
int nCurMinute = tmNow.Minute;

View File

@ -42,30 +42,24 @@ uint16_t WS2812FX::mode_static(void) {
* Blink/strobe function
* Alternate between color1 and color2
* 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 stateTime = SEGENV.aux1;
uint32_t cycleTime = (255 - SEGMENT.speed)*20;
uint32_t onTime = 0;
uint32_t offTime = cycleTime;
if (!strobe) {
onTime = (cycleTime * SEGMENT.intensity) >> 8;
offTime = cycleTime - onTime;
uint32_t onTime = FRAMETIME;
if (!strobe) onTime += ((cycleTime * SEGMENT.intensity) >> 8);
cycleTime += FRAMETIME*2;
uint32_t it = now / cycleTime;
uint32_t rem = now % cycleTime;
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;
stateTime += 20;
if (now - SEGENV.step > stateTime)
{
SEGENV.aux0++;
SEGENV.aux1 = stateTime;
SEGENV.step = now;
}
SEGENV.step = it; //save previous iteration
uint32_t color = ((SEGENV.aux0 & 1) == 0) ? color1 : color2;
uint32_t color = on ? color1 : color2;
if (color == color1 && do_palette)
{
for(uint16_t i = 0; i < SEGLEN; i++) {

View File

@ -75,7 +75,7 @@
#define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN _virtualSegmentLength
#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))
// some common colors

View File

@ -1036,7 +1036,10 @@ function requestJson(command, rinfo = true, verbose = true) {
d.getElementById('sliderIntensity').value = i.ix;
// 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');
if (selElement) {
selElement.classList.remove('selected')

View File

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

View File

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

View File

@ -5,6 +5,9 @@
/*
* Acquires time from NTP server
*/
//#define WLED_DEBUG_NTP
#define NTP_SYNC_INTERVAL 42000UL //Get fresh NTP time about twice per day
Timezone* tz;
#define TZ_UTC 0
@ -133,9 +136,28 @@ void updateTimezone() {
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()
{
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WLED_CONNECTED)
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > (1000*NTP_SYNC_INTERVAL) && WLED_CONNECTED)
{
if (millis() - ntpPacketSentTime > 10000)
{
@ -182,35 +204,52 @@ void sendNTPPacket()
bool checkNTPResponse()
{
int cb = ntpUdp.parsePacket();
if (cb) {
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
if (!cb) return false;
unsigned long highWord = word(pbuf[40], pbuf[41]);
unsigned long lowWord = word(pbuf[42], pbuf[43]);
if (highWord == 0 && lowWord == 0) return false;
unsigned long secsSince1900 = highWord << 16 | lowWord;
DEBUG_PRINT(F("Unix time = "));
unsigned long epoch = secsSince1900 - 2208988799UL; //subtract 70 years -1sec (on avg. more precision)
setTime(epoch);
DEBUG_PRINTLN(epoch);
if (countdownTime - now() > 0) countdownOverTriggered = false;
// if time changed re-calculate sunrise/sunset
updateLocalTime();
calculateSunriseAndSunset();
return true;
}
return false;
uint32_t ntpPacketReceivedTime = millis();
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
Toki::Time arrived = toki.fromNTP(pbuf + 32);
Toki::Time departed = toki.fromNTP(pbuf + 40);
if (departed.sec == 0) return false;
//basic half roundtrip estimation
uint32_t serverDelay = toki.msDifference(arrived, departed);
uint32_t offset = (ntpPacketReceivedTime - ntpPacketSentTime - serverDelay) >> 1;
#ifdef WLED_DEBUG_NTP
//the time the packet departed the NTP server
toki.printTime(departed);
#endif
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()
{
if (currentTimezone != tzCurrent) updateTimezone();
unsigned long tmc = now()+ utcOffsetSecs;
unsigned long tmc = toki.second()+ utcOffsetSecs;
localTime = tz->toLocal(tmc);
}
@ -234,13 +273,13 @@ void setCountdown()
{
if (currentTimezone != tzCurrent) updateTimezone();
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
bool checkCountdown()
{
unsigned long n = now();
unsigned long n = toki.second();
if (countdownMode) localTime = countdownTime - n + utcOffsetSecs;
if (n > countdownTime) {
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()
{
if (overlayCurrent == 3 && !cronixieInit)
if (overlayCurrent == 3 && dP[0] == 255) //if dP[0] is 255, cronixie is not yet init'ed
{
setCronixie();
strip.getSegment(0).grouping = 10; //10 LEDs per digit
cronixieInit = true;
} else if (cronixieInit && overlayCurrent != 3)
} else if (dP[0] < 255 && overlayCurrent != 3)
{
strip.getSegment(0).grouping = 1;
cronixieInit = false;
dP[0] = 255;
}
}
void handleOverlays()
{
if (millis() - overlayRefreshedTime > overlayRefreshMs)
{
initCronixie();
updateLocalTime();
checkTimers();
checkCountdown();
if (overlayCurrent == 3) _overlayCronixie();//Diamex cronixie clock kit
overlayRefreshedTime = millis();
initCronixie();
if (overlayCurrent == 3) {
_overlayCronixie();//Diamex cronixie clock kit
strip.trigger();
}
}
@ -73,15 +68,14 @@ void _overlayAnalogClock()
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000);
strip.setPixelColor(minutePixel, 0x00FF00);
strip.setPixelColor(hourPixel, 0x0000FF);
overlayRefreshMs = 998;
}
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;
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]);
}
}
overlayRefreshMs = 998;
}
@ -219,8 +212,6 @@ void setCronixie()
DEBUG_PRINT("cset ");
DEBUG_PRINTLN(cronixieDisplay);
overlayRefreshMs = 1997; //Only refresh every 2secs if no seconds are displayed
for (int i = 0; i < 6; i++)
{
@ -241,8 +232,8 @@ void setCronixie()
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] = 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] = 30 + getSameCodeLength('S',i,cronixieDisplay); i = i+dP[i]-30; overlayRefreshMs = 497; break;
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; 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 '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);
}
presetsModifiedTime = now(); //unix time
presetsModifiedTime = toki.second(); //unix time
updateFSInfo();
}
void deletePreset(byte index) {
StaticJsonDocument<24> empty;
writeObjectToFileUsingId("/presets.json", index, &empty);
presetsModifiedTime = now(); //unix time
presetsModifiedTime = toki.second(); //unix time
updateFSInfo();
}

View File

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

View File

@ -1,5 +1,9 @@
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.
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:
hour(); // the hour now (0-23)
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
The time and date functions take a parameter for the time. This prevents
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
following functions eliminates this probglem
time_t t = now(); // store the current time in time variable t
following functions eliminates this problem
hour(t); // returns the hour 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
@ -43,25 +31,6 @@ following functions eliminates this probglem
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
of time units.

View File

@ -25,6 +25,7 @@
examples, add error checking and messages to RTC examples,
add examples to DS1307RTC library.
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
@ -37,7 +38,6 @@
static tmElements_t tm; // a cache of time elements
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) {
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
refreshCache(t);
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
refreshCache(t);
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 ;
}
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
return !isPM(t);
}
uint8_t isPM() { // returns true if PM
return isPM(now());
}
uint8_t isPM(time_t t) { // returns true if PM
return (hour(t) >= 12);
}
int minute() {
return minute(now());
}
int minute(time_t t) { // the minute for the given time
refreshCache(t);
return tm.Minute;
}
int second() {
return second(now());
}
int second(time_t t) { // the second for the given time
refreshCache(t);
return tm.Second;
}
int day(){
return(day(now()));
}
int day(time_t t) { // the day for the given time (0-6)
refreshCache(t);
return tm.Day;
}
int weekday() { // Sunday is day 1
return weekday(now());
}
int weekday(time_t t) {
refreshCache(t);
return tm.Wday;
}
int month(){
return month(now());
}
int month(time_t t) { // the month for the given time
refreshCache(t);
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
refreshCache(t);
return tmYearToCalendar(tm.Year);
@ -231,57 +191,6 @@ time_t makeTime(tmElements_t &tm){
seconds+= tm.Second;
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){
// 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.Second = sec;
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
// nothing too terrible will result from overriding the C library header?!
extern "C++" {
typedef enum {timeNotSet, timeNeedsSync, timeSet
} timeStatus_t ;
typedef enum {
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
@ -95,33 +93,19 @@ typedef time_t(*getExternalTime)();
#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK)
/*============================================================================*/
/* time and date functions */
int hour(); // the hour now
/* time and date functions */
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
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 isPM(); // returns true if time now 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 second(); // the second now
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 weekday(); // the weekday now (Sunday is day 1)
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 year(); // the full four digit year: (2009, 2010 etc)
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
void adjustTime(long adjustment);
/* date strings */
#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* monthShortStr(uint8_t month);
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
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
*/
#define WLEDPACKETSIZE 29
#define WLEDPACKETSIZE 36
#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)
{
@ -37,8 +38,8 @@ void notify(byte callMode, bool followUp)
//compatibilityVersionByte:
//0: old 1: supports white 2: supports secondary color
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color
udpOut[11] = 7;
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet
udpOut[11] = 8;
udpOut[12] = colSec[0];
udpOut[13] = colSec[1];
udpOut[14] = colSec[2];
@ -59,6 +60,18 @@ void notify(byte callMode, bool followUp)
udpOut[26] = (t >> 16) & 0xFF;
udpOut[27] = (t >> 8) & 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;
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
if (millis() - notificationSentTime < 1000) return;
if (udpIn[1] > 199) return; //do not receive custom versions
//compatibilityVersionByte:
byte version = udpIn[11];
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
//apply colors from notification
@ -212,40 +228,66 @@ void handleNotifications()
col[0] = udpIn[3];
col[1] = udpIn[4];
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];
if (udpIn[11] > 1)
if (version > 1)
{
colSec[0] = udpIn[12];
colSec[1] = udpIn[13];
colSec[2] = udpIn[14];
colSec[3] = udpIn[15];
}
if (udpIn[11] > 5)
{
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)
if (version > 6)
{
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
}
}
}
bool timebaseUpdated = false;
//apply effects from notification
if (udpIn[11] < 200 && (receiveNotificationEffects || !someSel))
if (version < 200 && (receiveNotificationEffects || !someSel))
{
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
effectSpeed = udpIn[9];
if (udpIn[11] > 2) effectIntensity = udpIn[16];
if (udpIn[11] > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
if (version > 2) effectIntensity = udpIn[16];
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);
}

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,7 @@
#include <SPIFFSEditor.h>
#include "src/dependencies/time/TimeLib.h"
#include "src/dependencies/timezone/Timezone.h"
#include "src/dependencies/toki/Toki.h"
#ifndef WLED_DISABLE_ALEXA
#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 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 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
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
WLED_GLOBAL byte dP[] _INIT_N(({ 0, 0, 0, 0, 0, 0 }));
WLED_GLOBAL bool cronixieInit _INIT(false);
WLED_GLOBAL byte dP[] _INIT_N(({ 255, 255, 255, 255, 255, 255 }));
// countdown
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 time_t sunrise _INIT(0);
WLED_GLOBAL time_t sunset _INIT(0);
WLED_GLOBAL Toki toki _INIT(Toki());
// Temp buffer
WLED_GLOBAL char* obuf;

View File

@ -224,7 +224,10 @@ void initServer()
//make API CORS compatible
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;