Merge remote-tracking branch 'upstream/main' into mdev

This commit is contained in:
Ewoud
2023-02-06 21:06:13 +01:00
27 changed files with 4603 additions and 4258 deletions

View File

@@ -20,6 +20,7 @@
- usermod enhancements (PIR, Temperature, Battery (PR #2975), Analog Clock (PR #2993)) - usermod enhancements (PIR, Temperature, Battery (PR #2975), Analog Clock (PR #2993))
- new usermod SHT (PR #2963) - new usermod SHT (PR #2963)
- 2D matrix set up with gaps or irregular panels (breaking change!) (PR #2892) - 2D matrix set up with gaps or irregular panels (breaking change!) (PR #2892)
- palette blending/transitions
- random palette smooth changes - random palette smooth changes
- hex color notations in custom palettes - hex color notations in custom palettes
- allow more virtual buses - allow more virtual buses
@@ -34,6 +35,7 @@
- [internal] completely rewritten Segment & WS2812FX handling code - [internal] completely rewritten Segment & WS2812FX handling code
- [internal] ability to add custom effects via usermods - [internal] ability to add custom effects via usermods
- [internal] set of 2D drawing functions - [internal] set of 2D drawing functions
- transitions on every segment (including ESP8266)
- enhanced old and new 2D effects (metadata: default values) - enhanced old and new 2D effects (metadata: default values)
- custom palettes (up to 10; upload palette0.json, palette1.json, ...) - custom palettes (up to 10; upload palette0.json, palette1.json, ...)
- custom effect sliders and options, quick filters - custom effect sliders and options, quick filters
@@ -51,6 +53,7 @@
- allow disabling pull-up resistors on buttons - allow disabling pull-up resistors on buttons
- SD card support (PR #2877) - SD card support (PR #2877)
- enhanced HTTP API to support custom effect sliders & options (X1, X2, X3, M1, M2, M3) - enhanced HTTP API to support custom effect sliders & options (X1, X2, X3, M1, M2, M3)
- multiple UDP sync message retries (PR #2830)
- network debug printer (PR #2870) - network debug printer (PR #2870)
- automatic UI PC mode on large displays - automatic UI PC mode on large displays
- removed support for upgrading from pre-0.10 (EEPROM) - removed support for upgrading from pre-0.10 (EEPROM)

6
package-lock.json generated
View File

@@ -3845,9 +3845,9 @@
} }
}, },
"http-cache-semantics": { "http-cache-semantics": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
}, },
"http-signature": { "http-signature": {
"version": "1.2.0", "version": "1.2.0",

View File

@@ -22,8 +22,12 @@
//class name. Use something descriptive and leave the ": public Usermod" part :) //class name. Use something descriptive and leave the ": public Usermod" part :)
class MyExampleUsermod : public Usermod { class MyExampleUsermod : public Usermod {
private: private:
//Private class members. You can declare variables and functions only accessible to your usermod here
// Private class members. You can declare variables and functions only accessible to your usermod here
bool enabled = false;
bool initDone = false;
unsigned long lastTime = 0; unsigned long lastTime = 0;
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer) // set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
@@ -37,15 +41,56 @@ class MyExampleUsermod : public Usermod {
long testLong; long testLong;
int8_t testPins[2]; int8_t testPins[2];
// string that are used multiple time (this will save some flash memory)
static const char _name[];
static const char _enabled[];
// any private methods should go here (non-inline methosd should be defined out of class)
void publishMqtt(const char* state, bool retain = false); // example for publishing MQTT message
public: public:
//Functions called by WLED
// non WLED related methods, may be used for data exchange between usermods (non-inline methods should be defined out of class)
/**
* Enable/Disable the usermod
*/
inline void enable(bool enable) { enabled = enable; }
/**
* Get usermod enabled/disabled state
*/
inline bool isEnabled() { return enabled; }
// in such case add the following to another usermod:
// in private vars:
// #ifdef USERMOD_EXAMPLE
// MyExampleUsermod* UM;
// #endif
// in setup()
// #ifdef USERMOD_EXAMPLE
// UM = (MyExampleUsermod*) usermods.lookup(USERMOD_ID_EXAMPLE);
// #endif
// somewhere in loop() or other member method
// #ifdef USERMOD_EXAMPLE
// if (UM != nullptr) isExampleEnabled = UM->isEnabled();
// if (!isExampleEnabled) UM->enable(true);
// #endif
// methods called by WLED (can be inlined as they are called only once but if you call them explicitly define them out of class)
/* /*
* setup() is called once at boot. WiFi is not yet connected at this point. * setup() is called once at boot. WiFi is not yet connected at this point.
* readFromConfig() is called prior to setup()
* You can use it to initialize variables, sensors or similar. * You can use it to initialize variables, sensors or similar.
*/ */
void setup() { void setup() {
// do your set-up here
//Serial.println("Hello from my usermod!"); //Serial.println("Hello from my usermod!");
initDone = true;
} }
@@ -69,6 +114,11 @@ class MyExampleUsermod : public Usermod {
* Instead, use a timer check as shown here. * Instead, use a timer check as shown here.
*/ */
void loop() { void loop() {
// if usermod is disabled or called during strip updating just exit
// NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
if (!enabled || strip.isUpdating()) return;
// do your magic here
if (millis() - lastTime > 1000) { if (millis() - lastTime > 1000) {
//Serial.println("I'm alive!"); //Serial.println("I'm alive!");
lastTime = millis(); lastTime = millis();
@@ -81,19 +131,25 @@ class MyExampleUsermod : public Usermod {
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor * Below it is shown how this could be used for e.g. a light sensor
*/ */
/*
void addToJsonInfo(JsonObject& root) void addToJsonInfo(JsonObject& root)
{ {
int reading = 20; // if "u" object does not exist yet wee need to create it
//this code adds "u":{"Light":[20," lux"]} to the info object
JsonObject user = root["u"]; JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u"); if (user.isNull()) user = root.createNestedObject("u");
JsonArray lightArr = user.createNestedArray("Light"); //name //this code adds "u":{"ExampleUsermod":[20," lux"]} to the info object
lightArr.add(reading); //value //int reading = 20;
lightArr.add(" lux"); //unit //JsonArray lightArr = user.createNestedArray(FPSTR(_name))); //name
//lightArr.add(reading); //value
//lightArr.add(F(" lux")); //unit
// if you are implementing a sensor usermod, you may publish sensor data
//JsonObject sensor = root[F("sensor")];
//if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
//temp = sensor.createNestedArray(F("light"));
//temp.add(reading);
//temp.add(F("lux"));
} }
*/
/* /*
@@ -102,7 +158,12 @@ class MyExampleUsermod : public Usermod {
*/ */
void addToJsonState(JsonObject& root) void addToJsonState(JsonObject& root)
{ {
//root["user0"] = userVar0; if (!initDone || !enabled) return; // prevent crash on boot applyPreset()
JsonObject usermod = root[FPSTR(_name)];
if (usermod.isNull()) usermod = root.createNestedObject(FPSTR(_name));
//usermod["user0"] = userVar0;
} }
@@ -112,7 +173,14 @@ class MyExampleUsermod : public Usermod {
*/ */
void readFromJsonState(JsonObject& root) void readFromJsonState(JsonObject& root)
{ {
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value if (!initDone) return; // prevent crash on boot applyPreset()
JsonObject usermod = root[FPSTR(_name)];
if (!usermod.isNull()) {
// expect JSON usermod data in usermod name object: {"ExampleUsermod:{"user0":10}"}
userVar0 = usermod["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
}
// you can as well check WLED state JSON keys
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
} }
@@ -154,8 +222,10 @@ class MyExampleUsermod : public Usermod {
*/ */
void addToConfig(JsonObject& root) void addToConfig(JsonObject& root)
{ {
JsonObject top = root.createNestedObject("exampleUsermod"); JsonObject top = root.createNestedObject(FPSTR(_name));
top["great"] = userVar0; //save these vars persistently whenever settings are saved top[FPSTR(_enabled)] = enabled;
//save these vars persistently whenever settings are saved
top["great"] = userVar0;
top["testBool"] = testBool; top["testBool"] = testBool;
top["testInt"] = testInt; top["testInt"] = testInt;
top["testLong"] = testLong; top["testLong"] = testLong;
@@ -188,7 +258,7 @@ class MyExampleUsermod : public Usermod {
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor // default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed) // setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
JsonObject top = root["exampleUsermod"]; JsonObject top = root[FPSTR(_name)];
bool configComplete = !top.isNull(); bool configComplete = !top.isNull();
@@ -201,6 +271,8 @@ class MyExampleUsermod : public Usermod {
// A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing // A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing
configComplete &= getJsonValue(top["testInt"], testInt, 42); configComplete &= getJsonValue(top["testInt"], testInt, 42);
configComplete &= getJsonValue(top["testLong"], testLong, -42424242); configComplete &= getJsonValue(top["testLong"], testLong, -42424242);
// "pin" fields have special handling in settings page (or some_pin as well)
configComplete &= getJsonValue(top["pin"][0], testPins[0], -1); configComplete &= getJsonValue(top["pin"][0], testPins[0], -1);
configComplete &= getJsonValue(top["pin"][1], testPins[1], -1); configComplete &= getJsonValue(top["pin"][1], testPins[1], -1);
@@ -208,6 +280,21 @@ class MyExampleUsermod : public Usermod {
} }
/*
* appendConfigData() is called when user enters usermod settings page
* it may add additional metadata for certain entry fields (adding drop down is possible)
* be careful not to add too much as oappend() buffer is limited to 3k
*/
void appendConfigData()
{
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'<i>(this is a great config value)</i>');"));
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');"));
oappend(SET_F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F("','testInt');"));
oappend(SET_F("addOption(dd,'Nothing',0);"));
oappend(SET_F("addOption(dd,'Everything',42);"));
}
/* /*
* handleOverlayDraw() is called just before every show() (LED strip update frame) after effects have set the colors. * handleOverlayDraw() is called just before every show() (LED strip update frame) after effects have set the colors.
* Use this to blank out some LEDs or set them to a different color regardless of the set effect mode. * Use this to blank out some LEDs or set them to a different color regardless of the set effect mode.
@@ -218,7 +305,72 @@ class MyExampleUsermod : public Usermod {
//strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black //strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black
} }
/**
* handleButton() can be used to override default button behaviour. Returning true
* will prevent button working in a default way.
* Replicating button.cpp
*/
bool handleButton(uint8_t b) {
yield();
// ignore certain button types as they may have other consequences
if (!enabled
|| buttonType[b] == BTN_TYPE_NONE
|| buttonType[b] == BTN_TYPE_RESERVED
|| buttonType[b] == BTN_TYPE_PIR_SENSOR
|| buttonType[b] == BTN_TYPE_ANALOG
|| buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
return false;
}
bool handled = false;
// do your button handling here
return handled;
}
#ifndef WLED_DISABLE_MQTT
/**
* handling of MQTT message
* topic only contains stripped topic (part after /wled/MAC)
*/
bool onMqttMessage(char* topic, char* payload) {
// check if we received a command
//if (strlen(topic) == 8 && strncmp_P(topic, PSTR("/command"), 8) == 0) {
// String action = payload;
// if (action == "on") {
// enabled = true;
// return true;
// } else if (action == "off") {
// enabled = false;
// return true;
// } else if (action == "toggle") {
// enabled = !enabled;
// return true;
// }
//}
return false;
}
/**
* onMqttConnect() is called when MQTT connection is established
*/
void onMqttConnect(bool sessionPresent) {
// do any MQTT related initialisation here
//publishMqtt("I am alive!");
}
#endif
/**
* onStateChanged() is used to detect WLED state change
* @mode parameter is CALL_MODE_... parameter used for notifications
*/
void onStateChange(uint8_t mode) {
// do something if WLED state changed (color, brightness, effect, preset, etc)
}
/* /*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed. * This could be used in the future for the system to determine whether your usermod is installed.
@@ -230,4 +382,25 @@ class MyExampleUsermod : public Usermod {
//More methods can be added in the future, this example will then be extended. //More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class! //Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
}; };
// add more strings here to reduce flash memory usage
const char MyExampleUsermod::_name[] PROGMEM = "ExampleUsermod";
const char MyExampleUsermod::_enabled[] PROGMEM = "enabled";
// implementation of non-inline member methods
void MyExampleUsermod::publishMqtt(const char* state, bool retain)
{
#ifndef WLED_DISABLE_MQTT
//Check if MQTT Connected, otherwise it will crash the 8266
if (WLED_MQTT_CONNECTED) {
char subuf[64];
strcpy(subuf, mqttDeviceTopic);
strcat_P(subuf, PSTR("/example"));
mqtt->publish(subuf, 0, retain, state);
}
#endif
}

View File

@@ -110,6 +110,7 @@ private:
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return; //if lights on and off only, do nothing if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return; //if lights on and off only, do nothing
if (PIRtriggered && switchOn) return; //if already on and triggered before, do nothing if (PIRtriggered && switchOn) return; //if already on and triggered before, do nothing
PIRtriggered = switchOn; PIRtriggered = switchOn;
DEBUG_PRINT(F("PIR: strip=")); DEBUG_PRINTLN(switchOn?"on":"off");
if (switchOn) { if (switchOn) {
if (m_onPreset) { if (m_onPreset) {
if (currentPlaylist>0 && !offMode) { if (currentPlaylist>0 && !offMode) {
@@ -366,6 +367,19 @@ public:
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false; sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
} }
/**
* onStateChanged() is used to detect WLED state change
*/
void onStateChange(uint8_t mode) {
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
if (PIRtriggered && offTimerStart) {
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
DEBUG_PRINTLN(F("PIR: Canceled."));
offTimerStart = 0;
PIRtriggered = false;
}
}
/** /**
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients * Values in the state object may be modified by connected clients

View File

@@ -29,7 +29,11 @@
#include "fcn_declare.h" #include "fcn_declare.h"
#define IBN 5100 #define IBN 5100
#define PALETTE_SOLID_WRAP (strip.paletteBlend == 1 || strip.paletteBlend == 3)
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
#define PALETTE_SOLID_WRAP (strip.paletteBlend == 1 || strip.paletteBlend == 3)
#define PALETTE_MOVING_WRAP !(strip.paletteBlend == 2 || (strip.paletteBlend == 0 && SEGMENT.speed == 0))
#define indexToVStrip(index, stripNr) ((index) | (int((stripNr)+1)<<16)) #define indexToVStrip(index, stripNr) ((index) | (int((stripNr)+1)<<16))
// effect utility functions // effect utility functions
@@ -1923,11 +1927,10 @@ uint16_t mode_palette() {
counter = counter >> 8; counter = counter >> 8;
} }
bool noWrap = (strip.paletteBlend == 2 || (strip.paletteBlend == 0 && SEGMENT.speed == 0));
for (int i = 0; i < SEGLEN; i++) for (int i = 0; i < SEGLEN; i++)
{ {
uint8_t colorIndex = (i * 255 / SEGLEN) - counter; uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, noWrap, 255)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_MOVING_WRAP, 255));
} }
return FRAMETIME; return FRAMETIME;
@@ -3266,11 +3269,11 @@ uint16_t mode_exploding_fireworks(void)
if (SEGENV.aux0 < 2) { //FLARE if (SEGENV.aux0 < 2) { //FLARE
if (SEGENV.aux0 == 0) { //init flare if (SEGENV.aux0 == 0) { //init flare
flare->pos = 0; flare->pos = 0;
flare->posX = strip.isMatrix ? random16(2,cols-1) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D flare->posX = strip.isMatrix ? random16(2,cols-3) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D
uint16_t peakHeight = 75 + random8(180); //0-255 uint16_t peakHeight = 75 + random8(180); //0-255
peakHeight = (peakHeight * (rows -1)) >> 8; peakHeight = (peakHeight * (rows -1)) >> 8;
flare->vel = sqrtf(-2.0f * gravity * peakHeight); flare->vel = sqrtf(-2.0f * gravity * peakHeight);
flare->velX = strip.isMatrix ? (random8(8)-4)/32.f : 0; // no X velocity on 1D flare->velX = strip.isMatrix ? (random8(9)-4)/32.f : 0; // no X velocity on 1D
flare->col = 255; //brightness flare->col = 255; //brightness
SEGENV.aux0 = 1; SEGENV.aux0 = 1;
} }
@@ -3297,16 +3300,16 @@ uint16_t mode_exploding_fireworks(void)
* Size is proportional to the height. * Size is proportional to the height.
*/ */
int nSparks = flare->pos + random8(4); int nSparks = flare->pos + random8(4);
nSparks = constrain(nSparks, 1, numSparks); nSparks = constrain(nSparks, 4, numSparks);
// initialize sparks // initialize sparks
if (SEGENV.aux0 == 2) { if (SEGENV.aux0 == 2) {
for (int i = 1; i < nSparks; i++) { for (int i = 1; i < nSparks; i++) {
sparks[i].pos = flare->pos; sparks[i].pos = flare->pos;
sparks[i].posX = flare->posX; sparks[i].posX = flare->posX;
sparks[i].vel = (float(random16(0, 20000)) / 10000.0f) - 0.9f; // from -0.9 to 1.1 sparks[i].vel = (float(random16(20001)) / 10000.0f) - 0.9f; // from -0.9 to 1.1
sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips
sparks[i].velX = strip.isMatrix ? (float(random16(0, 4000)) / 10000.0f) - 0.2f : 0; // from -0.2 to 0.2 sparks[i].velX = strip.isMatrix ? (float(random16(10001)) / 10000.0f) - 0.5f : 0; // from -0.5 to 0.5
sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
//sparks[i].col = constrain(sparks[i].col, 0, 345); //sparks[i].col = constrain(sparks[i].col, 0, 345);
sparks[i].colIndex = random8(); sparks[i].colIndex = random8();

View File

@@ -420,8 +420,8 @@ void Segment::set(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t o
markForReset(); markForReset();
return; return;
} }
if (i1 < Segment::maxWidth) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D if (i1 < Segment::maxWidth || (i1 >= Segment::maxWidth*Segment::maxHeight && i1 < strip.getLengthTotal())) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D
stop = i2 > Segment::maxWidth ? Segment::maxWidth : MAX(1,i2); stop = i2 > Segment::maxWidth*Segment::maxHeight ? MIN(i2,strip.getLengthTotal()) : (i2 > Segment::maxWidth ? Segment::maxWidth : MAX(1,i2));
startY = 0; startY = 0;
stopY = 1; stopY = 1;
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
@@ -866,12 +866,14 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
} }
return; return;
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) { } else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) {
// we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed) if (start < Segment::maxWidth*Segment::maxHeight) {
int x = 0, y = 0; // we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed)
if (virtualHeight()>1) y = i; int x = 0, y = 0;
if (virtualWidth() >1) x = i; if (virtualHeight()>1) y = i;
setPixelColorXY(x, y, col); if (virtualWidth() >1) x = i;
return; setPixelColorXY(x, y, col);
return;
}
} }
#endif #endif
@@ -1741,6 +1743,20 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
_segments[i].spacing = 0; _segments[i].spacing = 0;
_mainSegment = i; _mainSegment = i;
} }
// do we have LEDs after the matrix? (ignore buses)
if (autoSegments && _length > Segment::maxWidth*Segment::maxHeight /*&& getActiveSegmentsNum() == 2*/) {
if (_segments.size() == getLastActiveSegmentId()+1)
_segments.push_back(Segment(Segment::maxWidth*Segment::maxHeight, _length));
else {
size_t i = getLastActiveSegmentId() + 1;
_segments[i].start = Segment::maxWidth*Segment::maxHeight;
_segments[i].stop = _length;
_segments[i].startY = 0;
_segments[i].stopY = 1;
_segments[i].grouping = 1;
_segments[i].spacing = 0;
}
}
#endif #endif
} else if (autoSegments) { //make one segment per bus } else if (autoSegments) { //make one segment per bus
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0}; uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
@@ -1764,6 +1780,7 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
s++; s++;
} }
_segments.clear(); _segments.clear();
_segments.reserve(s); // prevent reallocations
for (size_t i = 0; i < s; i++) { for (size_t i = 0; i < s; i++) {
Segment seg = Segment(segStarts[i], segStops[i]); Segment seg = Segment(segStarts[i], segStops[i]);
seg.selected = true; seg.selected = true;
@@ -1811,8 +1828,7 @@ bool WS2812FX::checkSegmentAlignment() {
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) //After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
//Note: If called in an interrupt (e.g. JSON API), original segment must be restored, //Note: If called in an interrupt (e.g. JSON API), original segment must be restored,
//otherwise it can lead to a crash on ESP32 because _segment_index is modified while in use by the main thread //otherwise it can lead to a crash on ESP32 because _segment_index is modified while in use by the main thread
uint8_t WS2812FX::setPixelSegment(uint8_t n) uint8_t WS2812FX::setPixelSegment(uint8_t n) {
{
uint8_t prevSegId = _segment_index; uint8_t prevSegId = _segment_index;
if (n < _segments.size()) { if (n < _segments.size()) {
_segment_index = n; _segment_index = n;
@@ -1821,8 +1837,7 @@ uint8_t WS2812FX::setPixelSegment(uint8_t n)
return prevSegId; return prevSegId;
} }
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) {
{
if (i2 >= i) if (i2 >= i)
{ {
for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col); for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col);
@@ -1832,14 +1847,12 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
} }
} }
void WS2812FX::setTransitionMode(bool t) void WS2812FX::setTransitionMode(bool t) {
{
for (segment &seg : _segments) if (!seg.transitional) seg.startTransition(t ? _transitionDur : 0); for (segment &seg : _segments) if (!seg.transitional) seg.startTransition(t ? _transitionDur : 0);
} }
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
void WS2812FX::printSize() void WS2812FX::printSize() {
{
size_t size = 0; size_t size = 0;
for (const Segment &seg : _segments) size += seg.getSize(); for (const Segment &seg : _segments) size += seg.getSize();
DEBUG_PRINTF("Segments: %d -> %uB\n", _segments.size(), size); DEBUG_PRINTF("Segments: %d -> %uB\n", _segments.size(), size);
@@ -1850,8 +1863,7 @@ void WS2812FX::printSize()
} }
#endif #endif
void WS2812FX::loadCustomPalettes() void WS2812FX::loadCustomPalettes() {
{
byte tcp[72]; //support gradient palettes with up to 18 entries byte tcp[72]; //support gradient palettes with up to 18 entries
CRGBPalette16 targetPalette; CRGBPalette16 targetPalette;
customPalettes.clear(); // start fresh customPalettes.clear(); // start fresh
@@ -1953,7 +1965,7 @@ void WS2812FX::deserializeMap(uint8_t n) {
customMappingSize = map.size(); customMappingSize = map.size();
customMappingTable = new uint16_t[customMappingSize]; customMappingTable = new uint16_t[customMappingSize];
for (uint16_t i=0; i<MIN(map.size(),customMappingSize); i++) { for (uint16_t i=0; i<MIN(map.size(),customMappingSize); i++) {
customMappingTable[i] = (uint16_t) map[i]; customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
} }
loadedLedmap = n; loadedLedmap = n;
setUpMatrix(false); //WLEDMM: apply logical to physical mapping after the ledmap setUpMatrix(false); //WLEDMM: apply logical to physical mapping after the ledmap
@@ -1967,11 +1979,6 @@ void WS2812FX::deserializeMap(uint8_t n) {
WS2812FX* WS2812FX::instance = nullptr; WS2812FX* WS2812FX::instance = nullptr;
//Bus static member definition, would belong in bus_manager.cpp
int16_t Bus::_cct = -1;
uint8_t Bus::_cctBlend = 0;
uint8_t Bus::_gAWM = 255;
const char JSON_mode_names[] PROGMEM = R"=====(["FX names moved"])====="; const char JSON_mode_names[] PROGMEM = R"=====(["FX names moved"])=====";
//WLEDMM netmindz ar palette add Audio responsive //WLEDMM netmindz ar palette add Audio responsive
const char JSON_palette_names[] PROGMEM = R"=====([ const char JSON_palette_names[] PROGMEM = R"=====([

540
wled00/bus_manager.cpp Normal file
View File

@@ -0,0 +1,540 @@
/*
* Class implementation for addressing various light types
*/
#include <Arduino.h>
#include <IPAddress.h>
#include "const.h"
#include "pin_manager.h"
#include "bus_wrapper.h"
#include "bus_manager.h"
//colors.cpp
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
uint16_t approximateKelvinFromRGB(uint32_t rgb);
void colorRGBtoRGBW(byte* rgb);
//udp.cpp
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false);
// enable additional debug output
#if defined(WLED_DEBUG_HOST)
#include "net_debug.h"
#define DEBUGOUT NetDebug
#else
#define DEBUGOUT Serial
#endif
#ifdef WLED_DEBUG
#ifndef ESP8266
#include <rom/rtc.h>
#endif
#define DEBUG_PRINT(x) DEBUGOUT.print(x)
#define DEBUG_PRINTLN(x) DEBUGOUT.println(x)
#define DEBUG_PRINTF(x...) DEBUGOUT.printf(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINTF(x...)
#endif
//color mangling macros
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
#define R(c) (byte((c) >> 16))
#define G(c) (byte((c) >> 8))
#define B(c) (byte(c))
#define W(c) (byte((c) >> 24))
void ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
if (_count >= WLED_MAX_COLOR_ORDER_MAPPINGS) {
return;
}
if (len == 0) {
return;
}
if (colorOrder > COL_ORDER_MAX) {
return;
}
_mappings[_count].start = start;
_mappings[_count].len = len;
_mappings[_count].colorOrder = colorOrder;
_count++;
}
uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const {
if (_count == 0) return defaultColorOrder;
// upper nibble containd W swap information
uint8_t swapW = defaultColorOrder >> 4;
for (uint8_t i = 0; i < _count; i++) {
if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) {
return _mappings[i].colorOrder | (swapW << 4);
}
}
return defaultColorOrder;
}
uint32_t Bus::autoWhiteCalc(uint32_t c) {
uint8_t aWM = _autoWhiteMode;
if (_gAWM < 255) aWM = _gAWM;
if (aWM == RGBW_MODE_MANUAL_ONLY) return c;
uint8_t w = W(c);
//ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0)
if (w > 0 && aWM == RGBW_MODE_DUAL) return c;
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
w = r < g ? (r < b ? r : b) : (g < b ? g : b);
if (aWM == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; } //subtract w in ACCURATE mode
return RGBW32(r, g, b, w);
}
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite), _colorOrderMap(com) {
if (!IS_DIGITAL(bc.type) || !bc.count) return;
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
_pins[0] = bc.pins[0];
if (IS_2PIN(bc.type)) {
if (!pinManager.allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
cleanup(); return;
}
_pins[1] = bc.pins[1];
}
reversed = bc.reversed;
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
_skip = bc.skipAmount; //sacrificial pixels
_len = bc.count + _skip;
_iType = PolyBus::getI(bc.type, _pins, nr);
if (_iType == I_NONE) return;
_busPtr = PolyBus::create(_iType, _pins, _len, nr);
_valid = (_busPtr != nullptr);
_colorOrder = bc.colorOrder;
DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, _len, bc.type, _pins[0],_pins[1],_iType);
}
void BusDigital::show() {
PolyBus::show(_busPtr, _iType);
}
bool BusDigital::canShow() {
return PolyBus::canShow(_busPtr, _iType);
}
void BusDigital::setBrightness(uint8_t b) {
//Fix for turning off onboard LED breaking bus
#ifdef LED_BUILTIN
if (_bri == 0 && b > 0) {
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
}
#endif
Bus::setBrightness(b);
PolyBus::setBrightness(_busPtr, _iType, b);
}
//If LEDs are skipped, it is possible to use the first as a status LED.
//TODO only show if no new show due in the next 50ms
void BusDigital::setStatusPixel(uint32_t c) {
if (_skip && canShow()) {
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
PolyBus::show(_busPtr, _iType);
}
}
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
if (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814) c = autoWhiteCalc(c);
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
if (reversed) pix = _len - pix -1;
else pix += _skip;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
}
uint32_t BusDigital::getPixelColor(uint16_t pix) {
if (reversed) pix = _len - pix -1;
else pix += _skip;
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
}
uint8_t BusDigital::getPins(uint8_t* pinArray) {
uint8_t numPins = IS_2PIN(_type) ? 2 : 1;
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
return numPins;
}
void BusDigital::setColorOrder(uint8_t colorOrder) {
// upper nibble contains W swap information
if ((colorOrder & 0x0F) > 5) return;
_colorOrder = colorOrder;
}
void BusDigital::reinit() {
PolyBus::begin(_busPtr, _iType, _pins);
}
void BusDigital::cleanup() {
DEBUG_PRINTLN(F("Digital Cleanup."));
PolyBus::cleanup(_busPtr, _iType);
_iType = I_NONE;
_valid = false;
_busPtr = nullptr;
pinManager.deallocatePin(_pins[1], PinOwner::BusDigital);
pinManager.deallocatePin(_pins[0], PinOwner::BusDigital);
}
BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
_valid = false;
if (!IS_PWM(bc.type)) return;
uint8_t numPins = NUM_PWM_PINS(bc.type);
#ifdef ESP8266
analogWriteRange(255); //same range as one RGB channel
analogWriteFreq(WLED_PWM_FREQ);
#else
_ledcStart = pinManager.allocateLedc(numPins);
if (_ledcStart == 255) { //no more free LEDC channels
deallocatePins(); return;
}
#endif
for (uint8_t i = 0; i < numPins; i++) {
uint8_t currentPin = bc.pins[i];
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) {
deallocatePins(); return;
}
_pins[i] = currentPin; //store only after allocatePin() succeeds
#ifdef ESP8266
pinMode(_pins[i], OUTPUT);
#else
ledcSetup(_ledcStart + i, WLED_PWM_FREQ, 8);
ledcAttachPin(_pins[i], _ledcStart + i);
#endif
}
reversed = bc.reversed;
_valid = true;
}
void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
if (pix != 0 || !_valid) return; //only react to first pixel
if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c);
if (_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
}
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
uint8_t w = W(c);
uint8_t cct = 0; //0 - full warm white, 255 - full cold white
if (_cct > -1) {
if (_cct >= 1900) cct = (_cct - 1900) >> 5;
else if (_cct < 256) cct = _cct;
} else {
cct = (approximateKelvinFromRGB(c) - 1900) >> 5;
}
uint8_t ww, cw;
#ifdef WLED_USE_IC_CCT
ww = w;
cw = cct;
#else
//0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold)
if (cct < _cctBlend) ww = 255;
else ww = ((255-cct) * 255) / (255 - _cctBlend);
if ((255-cct) < _cctBlend) cw = 255;
else cw = (cct * 255) / (255 - _cctBlend);
ww = (w * ww) / 255; //brightness scaling
cw = (w * cw) / 255;
#endif
switch (_type) {
case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation
_data[0] = w;
break;
case TYPE_ANALOG_2CH: //warm white + cold white
_data[1] = cw;
_data[0] = ww;
break;
case TYPE_ANALOG_5CH: //RGB + warm white + cold white
_data[4] = cw;
w = ww;
case TYPE_ANALOG_4CH: //RGBW
_data[3] = w;
case TYPE_ANALOG_3CH: //standard dumb RGB
_data[0] = r; _data[1] = g; _data[2] = b;
break;
}
}
//does no index check
uint32_t BusPwm::getPixelColor(uint16_t pix) {
if (!_valid) return 0;
return RGBW32(_data[0], _data[1], _data[2], _data[3]);
}
void BusPwm::show() {
if (!_valid) return;
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
uint8_t scaled = (_data[i] * _bri) / 255;
if (reversed) scaled = 255 - scaled;
#ifdef ESP8266
analogWrite(_pins[i], scaled);
#else
ledcWrite(_ledcStart + i, scaled);
#endif
}
}
uint8_t BusPwm::getPins(uint8_t* pinArray) {
if (!_valid) return 0;
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
pinArray[i] = _pins[i];
}
return numPins;
}
void BusPwm::deallocatePins() {
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm);
if (!pinManager.isPinOk(_pins[i])) continue;
#ifdef ESP8266
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
#else
if (_ledcStart < 16) ledcDetachPin(_pins[i]);
#endif
}
#ifdef ARDUINO_ARCH_ESP32
pinManager.deallocateLedc(_ledcStart, numPins);
#endif
}
BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
_valid = false;
if (bc.type != TYPE_ONOFF) return;
uint8_t currentPin = bc.pins[0];
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusOnOff)) {
return;
}
_pin = currentPin; //store only after allocatePin() succeeds
pinMode(_pin, OUTPUT);
reversed = bc.reversed;
_valid = true;
}
void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
if (pix != 0 || !_valid) return; //only react to first pixel
c = autoWhiteCalc(c);
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
uint8_t w = W(c);
_data = bool((r+g+b+w) && _bri) ? 0xFF : 0;
}
uint32_t BusOnOff::getPixelColor(uint16_t pix) {
if (!_valid) return 0;
return RGBW32(_data, _data, _data, _data);
}
void BusOnOff::show() {
if (!_valid) return;
digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data);
}
uint8_t BusOnOff::getPins(uint8_t* pinArray) {
if (!_valid) return 0;
pinArray[0] = _pin;
return 1;
}
BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
_valid = false;
// switch (bc.type) {
// case TYPE_NET_ARTNET_RGB:
// _rgbw = false;
// _UDPtype = 2;
// break;
// case TYPE_NET_E131_RGB:
// _rgbw = false;
// _UDPtype = 1;
// break;
// case TYPE_NET_DDP_RGB:
// _rgbw = false;
// _UDPtype = 0;
// break;
// default: // TYPE_NET_DDP_RGB / TYPE_NET_DDP_RGBW
_rgbw = bc.type == TYPE_NET_DDP_RGBW;
_UDPtype = 0;
// break;
// }
_UDPchannels = _rgbw ? 4 : 3;
_data = (byte *)malloc(bc.count * _UDPchannels);
if (_data == nullptr) return;
memset(_data, 0, bc.count * _UDPchannels);
_len = bc.count;
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
_broadcastLock = false;
_valid = true;
}
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
if (!_valid || pix >= _len) return;
if (isRgbw()) c = autoWhiteCalc(c);
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
uint16_t offset = pix * _UDPchannels;
_data[offset] = R(c);
_data[offset+1] = G(c);
_data[offset+2] = B(c);
if (_rgbw) _data[offset+3] = W(c);
}
uint32_t BusNetwork::getPixelColor(uint16_t pix) {
if (!_valid || pix >= _len) return 0;
uint16_t offset = pix * _UDPchannels;
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], _rgbw ? (_data[offset+3] << 24) : 0);
}
void BusNetwork::show() {
if (!_valid || !canShow()) return;
_broadcastLock = true;
realtimeBroadcast(_UDPtype, _client, _len, _data, _bri, _rgbw);
_broadcastLock = false;
}
uint8_t BusNetwork::getPins(uint8_t* pinArray) {
for (uint8_t i = 0; i < 4; i++) {
pinArray[i] = _client[i];
}
return 4;
}
void BusNetwork::cleanup() {
_type = I_NONE;
_valid = false;
if (_data != nullptr) free(_data);
_data = nullptr;
}
//utility to get the approx. memory usage of a given BusConfig
uint32_t BusManager::memUsage(BusConfig &bc) {
uint8_t type = bc.type;
uint16_t len = bc.count + bc.skipAmount;
if (type > 15 && type < 32) {
#ifdef ESP8266
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
if (type > 29) return len*20; //RGBW
return len*15;
}
if (type > 29) return len*4; //RGBW
return len*3;
#else //ESP32 RMT uses double buffer?
if (type > 29) return len*8; //RGBW
return len*6;
#endif
}
if (type > 31 && type < 48) return 5;
if (type == 44 || type == 45) return len*4; //RGBW
return len*3; //RGB
}
int BusManager::add(BusConfig &bc) {
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) {
busses[numBusses] = new BusNetwork(bc);
} else if (IS_DIGITAL(bc.type)) {
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap);
} else if (bc.type == TYPE_ONOFF) {
busses[numBusses] = new BusOnOff(bc);
} else {
busses[numBusses] = new BusPwm(bc);
}
return numBusses++;
}
//do not call this method from system context (network callback)
void BusManager::removeAll() {
DEBUG_PRINTLN(F("Removing all."));
//prevents crashes due to deleting busses while in use.
while (!canAllShow()) yield();
for (uint8_t i = 0; i < numBusses; i++) delete busses[i];
numBusses = 0;
}
void BusManager::show() {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->show();
}
}
void BusManager::setStatusPixel(uint32_t c) {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->setStatusPixel(c);
}
}
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) {
for (uint8_t i = 0; i < numBusses; i++) {
Bus* b = busses[i];
uint16_t bstart = b->getStart();
if (pix < bstart || pix >= bstart + b->getLength()) continue;
busses[i]->setPixelColor(pix - bstart, c);
}
}
void BusManager::setBrightness(uint8_t b) {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->setBrightness(b);
}
}
void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
if (cct > 255) cct = 255;
if (cct >= 0) {
//if white balance correction allowed, save as kelvin value instead of 0-255
if (allowWBCorrection) cct = 1900 + (cct << 5);
} else cct = -1;
Bus::setCCT(cct);
}
uint32_t BusManager::getPixelColor(uint16_t pix) {
for (uint8_t i = 0; i < numBusses; i++) {
Bus* b = busses[i];
uint16_t bstart = b->getStart();
if (pix < bstart || pix >= bstart + b->getLength()) continue;
return b->getPixelColor(pix - bstart);
}
return 0;
}
bool BusManager::canAllShow() {
for (uint8_t i = 0; i < numBusses; i++) {
if (!busses[i]->canShow()) return false;
}
return true;
}
Bus* BusManager::getBus(uint8_t busNr) {
if (busNr >= numBusses) return nullptr;
return busses[busNr];
}
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
uint16_t BusManager::getTotalLength() {
uint16_t len = 0;
for (uint8_t i=0; i<numBusses; i++) len += busses[i]->getLength();
return len;
}
// Bus static member definition
int16_t Bus::_cct = -1;
uint8_t Bus::_cctBlend = 0;
uint8_t Bus::_gAWM = 255;

View File

@@ -6,45 +6,11 @@
*/ */
#include "const.h" #include "const.h"
#include "pin_manager.h"
#include "bus_wrapper.h"
#include <Arduino.h>
//colors.cpp
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
void colorRGBtoRGBW(byte* rgb);
// enable additional debug output
#if defined(WLED_DEBUG_HOST)
#define DEBUGOUT NetDebug
#else
#define DEBUGOUT Serial
#endif
#ifdef WLED_DEBUG
#ifndef ESP8266
#include <rom/rtc.h>
#endif
#define DEBUG_PRINT(x) DEBUGOUT.print(x)
#define DEBUG_PRINTLN(x) DEBUGOUT.println(x)
#define DEBUG_PRINTF(x...) DEBUGOUT.printf(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINTF(x...)
#endif
#define GET_BIT(var,bit) (((var)>>(bit))&0x01) #define GET_BIT(var,bit) (((var)>>(bit))&0x01)
#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit))) #define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit)))) #define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
//color mangling macros
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
#define R(c) (byte((c) >> 16))
#define G(c) (byte((c) >> 8))
#define B(c) (byte(c))
#define W(c) (byte((c) >> 24))
//temporary struct for passing bus configuration to bus //temporary struct for passing bus configuration to bus
struct BusConfig { struct BusConfig {
uint8_t type; uint8_t type;
@@ -88,53 +54,29 @@ struct ColorOrderMapEntry {
}; };
struct ColorOrderMap { struct ColorOrderMap {
void add(uint16_t start, uint16_t len, uint8_t colorOrder) { void add(uint16_t start, uint16_t len, uint8_t colorOrder);
if (_count >= WLED_MAX_COLOR_ORDER_MAPPINGS) {
return;
}
if (len == 0) {
return;
}
if (colorOrder > COL_ORDER_MAX) {
return;
}
_mappings[_count].start = start;
_mappings[_count].len = len;
_mappings[_count].colorOrder = colorOrder;
_count++;
}
uint8_t count() const { uint8_t count() const {
return _count; return _count;
}
void reset() {
_count = 0;
memset(_mappings, 0, sizeof(_mappings));
}
const ColorOrderMapEntry* get(uint8_t n) const {
if (n > _count) {
return nullptr;
} }
return &(_mappings[n]);
}
inline uint8_t IRAM_ATTR getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const { void reset() {
if (_count == 0) return defaultColorOrder; _count = 0;
// upper nibble containd W swap information memset(_mappings, 0, sizeof(_mappings));
uint8_t swapW = defaultColorOrder >> 4; }
for (uint8_t i = 0; i < _count; i++) {
if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) { const ColorOrderMapEntry* get(uint8_t n) const {
return _mappings[i].colorOrder | (swapW << 4); if (n > _count) {
return nullptr;
} }
return &(_mappings[n]);
} }
return defaultColorOrder;
} uint8_t getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const;
private: private:
uint8_t _count; uint8_t _count;
ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS]; ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS];
}; };
//parent class of BusDigital, BusPwm, and BusNetwork //parent class of BusDigital, BusPwm, and BusNetwork
@@ -214,440 +156,155 @@ class Bus {
bool _valid; bool _valid;
bool _needsRefresh; bool _needsRefresh;
uint8_t _autoWhiteMode; uint8_t _autoWhiteMode;
static uint8_t _gAWM; // definition in FX_fcn.cpp static uint8_t _gAWM;
static int16_t _cct; // definition in FX_fcn.cpp static int16_t _cct;
static uint8_t _cctBlend; // definition in FX_fcn.cpp static uint8_t _cctBlend;
uint32_t autoWhiteCalc(uint32_t c) { uint32_t autoWhiteCalc(uint32_t c);
uint8_t aWM = _autoWhiteMode;
if (_gAWM < 255) aWM = _gAWM;
if (aWM == RGBW_MODE_MANUAL_ONLY) return c;
uint8_t w = W(c);
//ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0)
if (w > 0 && aWM == RGBW_MODE_DUAL) return c;
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
w = r < g ? (r < b ? r : b) : (g < b ? g : b);
if (aWM == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; } //subtract w in ACCURATE mode
return RGBW32(r, g, b, w);
}
}; };
class BusDigital : public Bus { class BusDigital : public Bus {
public: public:
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite), _colorOrderMap(com) { BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
if (!IS_DIGITAL(bc.type) || !bc.count) return;
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; inline void show();
_pins[0] = bc.pins[0];
if (IS_2PIN(bc.type)) { bool canShow();
if (!pinManager.allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
cleanup(); return; void setBrightness(uint8_t b);
}
_pins[1] = bc.pins[1]; void setStatusPixel(uint32_t c);
void setPixelColor(uint16_t pix, uint32_t c);
uint32_t getPixelColor(uint16_t pix);
uint8_t getColorOrder() {
return _colorOrder;
} }
reversed = bc.reversed;
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
_skip = bc.skipAmount; //sacrificial pixels
_len = bc.count + _skip;
_iType = PolyBus::getI(bc.type, _pins, nr);
if (_iType == I_NONE) return;
_busPtr = PolyBus::create(_iType, _pins, _len, nr);
_valid = (_busPtr != nullptr);
_colorOrder = bc.colorOrder;
DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, _len, bc.type, _pins[0],_pins[1],_iType);
};
inline void show() { uint16_t getLength() {
PolyBus::show(_busPtr, _iType); return _len - _skip;
}
inline bool canShow() {
return PolyBus::canShow(_busPtr, _iType);
}
void setBrightness(uint8_t b) {
//Fix for turning off onboard LED breaking bus
#ifdef LED_BUILTIN
if (_bri == 0 && b > 0) {
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
} }
#endif
Bus::setBrightness(b);
PolyBus::setBrightness(_busPtr, _iType, b);
}
//If LEDs are skipped, it is possible to use the first as a status LED. uint8_t getPins(uint8_t* pinArray);
//TODO only show if no new show due in the next 50ms
void setStatusPixel(uint32_t c) { void setColorOrder(uint8_t colorOrder);
if (_skip && canShow()) {
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); uint8_t skippedLeds() {
PolyBus::show(_busPtr, _iType); return _skip;
} }
}
void setPixelColor(uint16_t pix, uint32_t c) { void reinit();
if (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814) c = autoWhiteCalc(c);
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
if (reversed) pix = _len - pix -1;
else pix += _skip;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
}
uint32_t getPixelColor(uint16_t pix) { void cleanup();
if (reversed) pix = _len - pix -1;
else pix += _skip;
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
}
inline uint8_t getColorOrder() { ~BusDigital() {
return _colorOrder; cleanup();
} }
uint16_t getLength() {
return _len - _skip;
}
uint8_t getPins(uint8_t* pinArray) {
uint8_t numPins = IS_2PIN(_type) ? 2 : 1;
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
return numPins;
}
void setColorOrder(uint8_t colorOrder) {
// upper nibble contains W swap information
if ((colorOrder & 0x0F) > 5) return;
_colorOrder = colorOrder;
}
inline uint8_t skippedLeds() {
return _skip;
}
inline void reinit() {
PolyBus::begin(_busPtr, _iType, _pins);
}
void cleanup() {
DEBUG_PRINTLN(F("Digital Cleanup."));
PolyBus::cleanup(_busPtr, _iType);
_iType = I_NONE;
_valid = false;
_busPtr = nullptr;
pinManager.deallocatePin(_pins[1], PinOwner::BusDigital);
pinManager.deallocatePin(_pins[0], PinOwner::BusDigital);
}
~BusDigital() {
cleanup();
}
private: private:
uint8_t _colorOrder = COL_ORDER_GRB; uint8_t _colorOrder = COL_ORDER_GRB;
uint8_t _pins[2] = {255, 255}; uint8_t _pins[2] = {255, 255};
uint8_t _iType = I_NONE; uint8_t _iType = 0; //I_NONE;
uint8_t _skip = 0; uint8_t _skip = 0;
void * _busPtr = nullptr; void * _busPtr = nullptr;
const ColorOrderMap &_colorOrderMap; const ColorOrderMap &_colorOrderMap;
}; };
class BusPwm : public Bus { class BusPwm : public Bus {
public: public:
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { BusPwm(BusConfig &bc);
_valid = false;
if (!IS_PWM(bc.type)) return;
uint8_t numPins = NUM_PWM_PINS(bc.type);
#ifdef ESP8266 void setPixelColor(uint16_t pix, uint32_t c);
analogWriteRange(255); //same range as one RGB channel
analogWriteFreq(WLED_PWM_FREQ);
#else
_ledcStart = pinManager.allocateLedc(numPins);
if (_ledcStart == 255) { //no more free LEDC channels
deallocatePins(); return;
}
#endif
for (uint8_t i = 0; i < numPins; i++) { //does no index check
uint8_t currentPin = bc.pins[i]; uint32_t getPixelColor(uint16_t pix);
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) {
deallocatePins(); return;
}
_pins[i] = currentPin; //store only after allocatePin() succeeds
#ifdef ESP8266
pinMode(_pins[i], OUTPUT);
#else
ledcSetup(_ledcStart + i, WLED_PWM_FREQ, 8);
ledcAttachPin(_pins[i], _ledcStart + i);
#endif
}
reversed = bc.reversed;
_valid = true;
};
void setPixelColor(uint16_t pix, uint32_t c) { void show();
if (pix != 0 || !_valid) return; //only react to first pixel
if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c); uint8_t getPins(uint8_t* pinArray);
if (_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
c = colorBalanceFromKelvin(_cct, c); //color correction from CCT void cleanup() {
} deallocatePins();
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
uint8_t w = W(c);
uint8_t cct = 0; //0 - full warm white, 255 - full cold white
if (_cct > -1) {
if (_cct >= 1900) cct = (_cct - 1900) >> 5;
else if (_cct < 256) cct = _cct;
} else {
cct = (approximateKelvinFromRGB(c) - 1900) >> 5;
} }
uint8_t ww, cw; ~BusPwm() {
#ifdef WLED_USE_IC_CCT cleanup();
ww = w;
cw = cct;
#else
//0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold)
if (cct < _cctBlend) ww = 255;
else ww = ((255-cct) * 255) / (255 - _cctBlend);
if ((255-cct) < _cctBlend) cw = 255;
else cw = (cct * 255) / (255 - _cctBlend);
ww = (w * ww) / 255; //brightness scaling
cw = (w * cw) / 255;
#endif
switch (_type) {
case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation
_data[0] = w;
break;
case TYPE_ANALOG_2CH: //warm white + cold white
_data[1] = cw;
_data[0] = ww;
break;
case TYPE_ANALOG_5CH: //RGB + warm white + cold white
_data[4] = cw;
w = ww;
case TYPE_ANALOG_4CH: //RGBW
_data[3] = w;
case TYPE_ANALOG_3CH: //standard dumb RGB
_data[0] = r; _data[1] = g; _data[2] = b;
break;
} }
}
//does no index check
uint32_t getPixelColor(uint16_t pix) {
if (!_valid) return 0;
return RGBW32(_data[0], _data[1], _data[2], _data[3]);
}
void show() {
if (!_valid) return;
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
uint8_t scaled = (_data[i] * _bri) / 255;
if (reversed) scaled = 255 - scaled;
#ifdef ESP8266
analogWrite(_pins[i], scaled);
#else
ledcWrite(_ledcStart + i, scaled);
#endif
}
}
uint8_t getPins(uint8_t* pinArray) {
if (!_valid) return 0;
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
pinArray[i] = _pins[i];
}
return numPins;
}
void cleanup() {
deallocatePins();
}
~BusPwm() {
cleanup();
}
private: private:
uint8_t _pins[5] = {255, 255, 255, 255, 255}; uint8_t _pins[5] = {255, 255, 255, 255, 255};
uint8_t _data[5] = {0}; uint8_t _data[5] = {0};
#ifdef ARDUINO_ARCH_ESP32
uint8_t _ledcStart = 255;
#endif
void deallocatePins() {
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm);
if (!pinManager.isPinOk(_pins[i])) continue;
#ifdef ESP8266
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
#else
if (_ledcStart < 16) ledcDetachPin(_pins[i]);
#endif
}
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
pinManager.deallocateLedc(_ledcStart, numPins); uint8_t _ledcStart = 255;
#endif #endif
}
void deallocatePins();
}; };
class BusOnOff : public Bus { class BusOnOff : public Bus {
public: public:
BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { BusOnOff(BusConfig &bc);
_valid = false;
if (bc.type != TYPE_ONOFF) return;
uint8_t currentPin = bc.pins[0]; void setPixelColor(uint16_t pix, uint32_t c);
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusOnOff)) {
return; uint32_t getPixelColor(uint16_t pix);
void show();
uint8_t getPins(uint8_t* pinArray);
void cleanup() {
pinManager.deallocatePin(_pin, PinOwner::BusOnOff);
} }
_pin = currentPin; //store only after allocatePin() succeeds
pinMode(_pin, OUTPUT);
reversed = bc.reversed;
_valid = true;
};
void setPixelColor(uint16_t pix, uint32_t c) { ~BusOnOff() {
if (pix != 0 || !_valid) return; //only react to first pixel cleanup();
c = autoWhiteCalc(c); }
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
uint8_t w = W(c);
_data = bool((r+g+b+w) && _bri) ? 0xFF : 0;
}
uint32_t getPixelColor(uint16_t pix) {
if (!_valid) return 0;
return RGBW32(_data, _data, _data, _data);
}
void show() {
if (!_valid) return;
digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data);
}
uint8_t getPins(uint8_t* pinArray) {
if (!_valid) return 0;
pinArray[0] = _pin;
return 1;
}
void cleanup() {
pinManager.deallocatePin(_pin, PinOwner::BusOnOff);
}
~BusOnOff() {
cleanup();
}
private: private:
uint8_t _pin = 255; uint8_t _pin = 255;
uint8_t _data = 0; uint8_t _data = 0;
}; };
class BusNetwork : public Bus { class BusNetwork : public Bus {
public: public:
BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { BusNetwork(BusConfig &bc);
_valid = false;
// switch (bc.type) {
// case TYPE_NET_ARTNET_RGB:
// _rgbw = false;
// _UDPtype = 2;
// break;
// case TYPE_NET_E131_RGB:
// _rgbw = false;
// _UDPtype = 1;
// break;
// case TYPE_NET_DDP_RGB:
// _rgbw = false;
// _UDPtype = 0;
// break;
// default: // TYPE_NET_DDP_RGB / TYPE_NET_DDP_RGBW
_rgbw = bc.type == TYPE_NET_DDP_RGBW;
_UDPtype = 0;
// break;
// }
_UDPchannels = _rgbw ? 4 : 3;
_data = (byte *)malloc(bc.count * _UDPchannels);
if (_data == nullptr) return;
memset(_data, 0, bc.count * _UDPchannels);
_len = bc.count;
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
_broadcastLock = false;
_valid = true;
};
bool hasRGB() { return true; } bool hasRGB() { return true; }
bool hasWhite() { return _rgbw; } bool hasWhite() { return _rgbw; }
void setPixelColor(uint16_t pix, uint32_t c) { void setPixelColor(uint16_t pix, uint32_t c);
if (!_valid || pix >= _len) return;
if (isRgbw()) c = autoWhiteCalc(c);
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
uint16_t offset = pix * _UDPchannels;
_data[offset] = R(c);
_data[offset+1] = G(c);
_data[offset+2] = B(c);
if (_rgbw) _data[offset+3] = W(c);
}
uint32_t getPixelColor(uint16_t pix) { uint32_t getPixelColor(uint16_t pix);
if (!_valid || pix >= _len) return 0;
uint16_t offset = pix * _UDPchannels;
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], _rgbw ? (_data[offset+3] << 24) : 0);
}
void show() { void show();
if (!_valid || !canShow()) return;
_broadcastLock = true;
realtimeBroadcast(_UDPtype, _client, _len, _data, _bri, _rgbw);
_broadcastLock = false;
}
inline bool canShow() { bool canShow() {
// this should be a return value from UDP routine if it is still sending data out // this should be a return value from UDP routine if it is still sending data out
return !_broadcastLock; return !_broadcastLock;
}
uint8_t getPins(uint8_t* pinArray) {
for (uint8_t i = 0; i < 4; i++) {
pinArray[i] = _client[i];
} }
return 4;
}
inline bool isRgbw() { uint8_t getPins(uint8_t* pinArray);
return _rgbw;
}
inline uint16_t getLength() { bool isRgbw() {
return _len; return _rgbw;
} }
void cleanup() { uint16_t getLength() {
_type = I_NONE; return _len;
_valid = false; }
if (_data != nullptr) free(_data);
_data = nullptr;
}
~BusNetwork() { void cleanup();
cleanup();
} ~BusNetwork() {
cleanup();
}
private: private:
IPAddress _client; IPAddress _client;
@@ -661,154 +318,56 @@ class BusNetwork : public Bus {
class BusManager { class BusManager {
public: public:
BusManager() {}; BusManager() {};
//utility to get the approx. memory usage of a given BusConfig //utility to get the approx. memory usage of a given BusConfig
static uint32_t memUsage(BusConfig &bc) { static uint32_t memUsage(BusConfig &bc);
uint8_t type = bc.type;
uint16_t len = bc.count + bc.skipAmount; int add(BusConfig &bc);
if (type > 15 && type < 32) {
#ifdef ESP8266 //do not call this method from system context (network callback)
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem void removeAll();
if (type > 29) return len*20; //RGBW
return len*15; void show();
}
if (type > 29) return len*4; //RGBW void setStatusPixel(uint32_t c);
return len*3;
#else //ESP32 RMT uses double buffer? void IRAM_ATTR setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
if (type > 29) return len*8; //RGBW
return len*6; void setBrightness(uint8_t b);
#endif
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
uint32_t getPixelColor(uint16_t pix);
bool canAllShow();
Bus* getBus(uint8_t busNr);
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
uint16_t getTotalLength();
inline void updateColorOrderMap(const ColorOrderMap &com) {
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
} }
if (type > 31 && type < 48) return 5;
if (type == 44 || type == 45) return len*4; //RGBW
return len*3; //RGB
}
/* inline const ColorOrderMap& getColorOrderMap() const {
int add(BusConfig &bc); return colorOrderMap;
void removeAll(); //do not call this method from system context (network callback)
void setStatusPixel(uint32_t c);
void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
void setBrightness(uint8_t b);
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
uint32_t getPixelColor(uint16_t pix);
bool canAllShow();
Bus* getBus(uint8_t busNr);
void show();
uint16_t getTotalLength(); //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
*/
// the following functions are inlined by compiler since they are defined within class definition
// they should be placed in cpp file instead
int add(BusConfig &bc) {
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) {
busses[numBusses] = new BusNetwork(bc);
} else if (IS_DIGITAL(bc.type)) {
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap);
} else if (bc.type == TYPE_ONOFF) {
busses[numBusses] = new BusOnOff(bc);
} else {
busses[numBusses] = new BusPwm(bc);
} }
return numBusses++;
}
//do not call this method from system context (network callback) inline uint8_t getNumBusses() {
void removeAll() { return numBusses;
DEBUG_PRINTLN(F("Removing all."));
//prevents crashes due to deleting busses while in use.
while (!canAllShow()) yield();
for (uint8_t i = 0; i < numBusses; i++) delete busses[i];
numBusses = 0;
}
void show() {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->show();
} }
}
void setStatusPixel(uint32_t c) {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->setStatusPixel(c);
}
}
void IRAM_ATTR setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1) {
for (uint8_t i = 0; i < numBusses; i++) {
Bus* b = busses[i];
uint16_t bstart = b->getStart();
if (pix < bstart || pix >= bstart + b->getLength()) continue;
busses[i]->setPixelColor(pix - bstart, c);
}
}
void setBrightness(uint8_t b) {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->setBrightness(b);
}
}
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false) {
if (cct > 255) cct = 255;
if (cct >= 0) {
//if white balance correction allowed, save as kelvin value instead of 0-255
if (allowWBCorrection) cct = 1900 + (cct << 5);
} else cct = -1;
Bus::setCCT(cct);
}
uint32_t getPixelColor(uint16_t pix) {
for (uint8_t i = 0; i < numBusses; i++) {
Bus* b = busses[i];
uint16_t bstart = b->getStart();
if (pix < bstart || pix >= bstart + b->getLength()) continue;
return b->getPixelColor(pix - bstart);
}
return 0;
}
bool canAllShow() {
for (uint8_t i = 0; i < numBusses; i++) {
if (!busses[i]->canShow()) return false;
}
return true;
}
Bus* getBus(uint8_t busNr) {
if (busNr >= numBusses) return nullptr;
return busses[busNr];
}
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
uint16_t getTotalLength() {
uint16_t len = 0;
for (uint8_t i=0; i<numBusses; i++) len += busses[i]->getLength();
return len;
}
inline void updateColorOrderMap(const ColorOrderMap &com) {
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
}
inline const ColorOrderMap& getColorOrderMap() const {
return colorOrderMap;
}
inline uint8_t getNumBusses() {
return numBusses;
}
private: private:
uint8_t numBusses = 0; uint8_t numBusses = 0;
Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
ColorOrderMap colorOrderMap; ColorOrderMap colorOrderMap;
inline uint8_t getNumVirtualBusses() { inline uint8_t getNumVirtualBusses() {
int j = 0; int j = 0;
for (int i=0; i<numBusses; i++) if (busses[i]->getType() >= TYPE_NET_DDP_RGB && busses[i]->getType() < 96) j++; for (int i=0; i<numBusses; i++) if (busses[i]->getType() >= TYPE_NET_DDP_RGB && busses[i]->getType() < 96) j++;
return j; return j;
} }
}; };
#endif #endif

View File

@@ -731,7 +731,7 @@ function populateSegments(s)
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`; let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`;
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`; let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`;
let rvYck = "", miYck =""; let rvYck = "", miYck ="";
if (isM) { if (isM && staX<mw*mh) {
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`; rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`;
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`; miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`;
} }
@@ -775,19 +775,19 @@ function populateSegments(s)
<input type="text" class="ptxt noslide" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/> <input type="text" class="ptxt noslide" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>
<table class="infot segt"> <table class="infot segt">
<tr> <tr>
<td>${isM?'Start X':'Start LED'}</td> <td>${isM&&staX<mw*mh?'Start X':'Start LED'}</td>
<td>${isM?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td> <td>${isM&&staX<mw*mh?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>
<td>${isM?'':'Offset'}</td> <td>${isM&&staX<mw*mh?'':'Offset'}</td>
</tr> </tr>
<tr> <tr>
<td><input class="noslide segn" id="seg${i}s" type="number" min="0" max="${(isM?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td> <td><input class="noslide segn" id="seg${i}s" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td><input class="noslide segn" id="seg${i}e" type="number" min="0" max="${(isM?mw:ledCount)-(cfg.comp.seglen?staX:0)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td> <td><input class="noslide segn" id="seg${i}e" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td style="text-align:revert;">${isM?miXck+'<br>'+rvXck:''}<input class="noslide segn ${isM?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td> <td style="text-align:revert;">${isM&&staX<mw*mh?miXck+'<br>'+rvXck:''}<input class="noslide segn ${isM&&staX<mw*mh?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>
</tr> </tr>
${isM ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></td></tr>'+ ${isM&&staX<mw*mh ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></td></tr>'+
'<tr>'+ '<tr>'+
'<td><input class="noslide segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+ '<td><input class="noslide segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
'<td><input class="noslide segn" id="seg'+i+'eY" type="number" min="0" max="'+(mh-(cfg.comp.seglen?staY:0))+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+ '<td><input class="noslide segn" id="seg'+i+'eY" type="number" min="0" max="'+mh+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
'<td style="text-align:revert;">'+miYck+'<br>'+rvYck+'</td>'+ '<td style="text-align:revert;">'+miYck+'<br>'+rvYck+'</td>'+
'</tr>':''} '</tr>':''}
<tr> <tr>
@@ -798,17 +798,18 @@ function populateSegments(s)
<tr> <tr>
<td><input class="noslide segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td> <td><input class="noslide segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td><input class="noslide segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td> <td><input class="noslide segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td style="text-align:left;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}">&#xe390;</i></button></td> <td style="text-align:revert;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}">&#xe390;</i></button></td>
</tr> </tr>
</table> </table>
<div class="h bp" id="seg${i}len"></div> <div class="h bp" id="seg${i}len"></div>
${!isM?rvXck:''} ${!(isM&&staX<mw*mh)?rvXck:''}
${isM&&stoY-staY>1&&stoX-staX>1?map2D:''} ${isM&&staX<mw*mh&&stoY-staY>1&&stoX-staX>1?map2D:''}
${s.AudioReactive && s.AudioReactive.on ? "" : sndSim} ${s.AudioReactive && s.AudioReactive.on ? "" : sndSim}
${s.CustomEffects && s.CustomEffects.on && fxName.includes("Custom Effect") ? cusEff : ""} ${s.CustomEffects && s.CustomEffects.on && fxName.includes("Custom Effect") ? cusEff : ""}
<label class="check revchkl" id="seg${i}lbtm"> <label class="check revchkl" id="seg${i}lbtm">
${isM?'Transpose':'Mirror effect'} ${isM&&staX<mw*mh?'Transpose':'Mirror effect'}${isM&&staX<mw*mh?
<input type="checkbox" id="seg${i}${isM?'tp':'mi'}" onchange="${(isM?'setTp(':'setMi(')+i})" ${isM?(inst.tp?"checked":""):(inst.mi?"checked":"")}> '<input type="checkbox" id="seg'+i+'tp" onchange="setTp('+i+')" '+(inst.tp?"checked":"")+'>':
'<input type="checkbox" id="seg'+i+'mi" onchange="setMi('+i+')" '+(inst.mi?"checked":"")+'>'}
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
<div class="del"> <div class="del">
@@ -1078,29 +1079,50 @@ function updateLen(s)
var start = parseInt(gId(`seg${s}s`).value); var start = parseInt(gId(`seg${s}s`).value);
var stop = parseInt(gId(`seg${s}e`).value) + (cfg.comp.seglen?start:0); var stop = parseInt(gId(`seg${s}e`).value) + (cfg.comp.seglen?start:0);
var len = stop - start; var len = stop - start;
let sY = gId(`seg${s}sY`);
let eY = gId(`seg${s}eY`);
let sX = gId(`seg${s}s`);
let eX = gId(`seg${s}e`);
let of = gId(`seg${s}of`);
let mySH = gId("mkSYH");
let mySD = gId("mkSYD");
if (isM) { if (isM) {
// matrix setup // do we have 1D segment *after* the matrix?
let startY = parseInt(gId(`seg${s}sY`).value); if (start >= mw*mh) {
let stopY = parseInt(gId(`seg${s}eY`).value) + (cfg.comp.seglen?startY:0); if (sY) { sY.value = 0; sY.max = 0; sY.min = 0; }
len *= (stopY-startY); if (eY) { eY.value = 1; eY.max = 1; eY.min = 0; }
let tPL = gId(`seg${s}lbtm`); sX.min = mw*mh; sX.max = ledCount-1;
if (stop-start>1 && stopY-startY>1) { eX.min = mw*mh+1; eX.max = ledCount;
// 2D segment if (mySH) mySH.classList.add("hide");
if (tPL) tPL.classList.remove('hide'); // unhide transpose checkbox if (mySD) mySD.classList.add("hide");
let sE = gId('fxlist').querySelector(`.lstI[data-id="${selectedFx}"]`); if (of) of.classList.remove("hide");
if (sE) {
let sN = sE.querySelector(".lstIname").innerText;
let seg = gId(`seg${s}map2D`);
if (seg) {
if(sN.indexOf("\u25A6")<0) seg.classList.remove('hide'); // unhide mapping for 1D effects (| in name)
else seg.classList.add('hide'); // hide mapping otherwise
}
}
} else { } else {
// 1D segment in 2D set-up // matrix setup
if (tPL) { if (mySH) mySH.classList.remove("hide");
tPL.classList.add('hide'); // hide transpose checkbox if (mySD) mySD.classList.remove("hide");
gId(`seg${s}tp`).checked = false; // and uncheck it if (of) of.classList.add("hide");
let startY = parseInt(sY.value);
let stopY = parseInt(eY.value) + (cfg.comp.seglen?startY:0);
len *= (stopY-startY);
let tPL = gId(`seg${s}lbtm`);
if (stop-start>1 && stopY-startY>1) {
// 2D segment
if (tPL) tPL.classList.remove('hide'); // unhide transpose checkbox
let sE = gId('fxlist').querySelector(`.lstI[data-id="${selectedFx}"]`);
if (sE) {
let sN = sE.querySelector(".lstIname").innerText;
let seg = gId(`seg${s}map2D`);
if (seg) {
if(sN.indexOf("\u25A6")<0) seg.classList.remove('hide'); // unhide mapping for 1D effects (| in name)
else seg.classList.add('hide'); // hide mapping otherwise
}
}
} else {
// 1D segment in 2D set-up
if (tPL) {
tPL.classList.add('hide'); // hide transpose checkbox
gId(`seg${s}tp`).checked = false; // and uncheck it
}
} }
} }
} }
@@ -1119,6 +1141,7 @@ function updateLen(s)
var virt = Math.ceil(len/(grp + spc)); var virt = Math.ceil(len/(grp + spc));
if (!isNaN(virt) && (grp > 1 || spc > 0)) out += ` (${virt} virtual)`; if (!isNaN(virt) && (grp > 1 || spc > 0)) out += ` (${virt} virtual)`;
} }
if (isM && start >= mw*mh) out += " [strip]";
gId(`seg${s}len`).innerHTML = out; gId(`seg${s}len`).innerHTML = out;
draw(); draw();
@@ -1840,11 +1863,11 @@ function makeSeg()
<td><input class="noslide segn" id="seg${lu}e" type="number" min="0" max="${ct}" value="${ct}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td> <td><input class="noslide segn" id="seg${lu}e" type="number" min="0" max="${ct}" value="${ct}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
<td><button class="btn btn-xs" onclick="setSeg(${lu});"><i class="icons bth-icon" id="segc${lu}">&#xe390;</i></button></td> <td><button class="btn btn-xs" onclick="setSeg(${lu});"><i class="icons bth-icon" id="segc${lu}">&#xe390;</i></button></td>
</tr> </tr>
${isM ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td></tr>'+ <tr id="mkSYH" class="${isM?"":"hide"}"><td>Start Y</td><td>${cfg.comp.seglen?'Height':'Stop Y'}</td></tr>
'<tr>'+ <tr id="mkSYD" class="${isM?"":"hide"}">
'<td><input class="noslide segn" id="seg'+lu+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+0+'" oninput="updateLen('+lu+')" onkeydown="segEnter('+lu+')"></td>'+ <td><input class="noslide segn" id="seg${lu}sY" type="number" min="0" max="${mh-1}" value="0" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
'<td><input class="noslide segn" id="seg'+lu+'eY" type="number" min="0" max="'+mh+'" value="'+mh+'" oninput="updateLen('+lu+')" onkeydown="segEnter('+lu+')"></td>'+ <td><input class="noslide segn" id="seg${lu}eY" type="number" min="0" max="${mh}" value="${isM?mh:1}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
'</tr>':''} </tr>
</table> </table>
<div class="h" id="seg${lu}len">${ledCount - ns} LEDs</div> <div class="h" id="seg${lu}len">${ledCount - ns} LEDs</div>
<div class="c"><button class="btn btn-p" onclick="resetUtil()">Cancel</button></div> <div class="c"><button class="btn btn-p" onclick="resetUtil()">Cancel</button></div>
@@ -2174,25 +2197,26 @@ function setSeg(s)
let sX = gId(`seg${s}s`); let sX = gId(`seg${s}s`);
let eX = gId(`seg${s}e`); let eX = gId(`seg${s}e`);
var start = parseInt(sX.value); var start = parseInt(sX.value);
var stop = parseInt(eX.value); var stop = parseInt(eX.value) + (cfg.comp.seglen?start:0);
if (start<sX.min || start>sX.max) {sX.value=sX.min; return;} // prevent out of bounds if (start<sX.min || start>sX.max) {sX.value=sX.min; return;} // prevent out of bounds
if (stop<eX.min || stop>eX.max) {eX.value=eX.max; return;} // prevent out of bounds if (stop<eX.min || stop-(cfg.comp.seglen?start:0)>eX.max) {eX.value=eX.max; return;} // prevent out of bounds
if ((cfg.comp.seglen && stop == 0) || (!cfg.comp.seglen && stop <= start)) {delSeg(s); return;} if ((cfg.comp.seglen && stop == 0) || (!cfg.comp.seglen && stop <= start)) {delSeg(s); return;}
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop}}; var obj = {"seg": {"id": s, "n": name, "start": start, "stop": stop}};
if (isM) { if (isM && start<mw*mh) {
let sY = gId(`seg${s}sY`); let sY = gId(`seg${s}sY`);
let eY = gId(`seg${s}eY`); let eY = gId(`seg${s}eY`);
var startY = parseInt(sY.value); var startY = parseInt(sY.value);
var stopY = parseInt(eY.value); var stopY = parseInt(eY.value) + (cfg.comp.seglen?startY:0);
if (startY<sY.min || startY>sY.max) {sY.value=sY.min; return;} // prevent out of bounds if (startY<sY.min || startY>sY.max) {sY.value=sY.min; return;} // prevent out of bounds
if (stopY<eY.min || stopY>eY.max) {eY.value=eY.max; return;} // prevent out of bounds if (stopY<eY.min || stopY>eY.max) {eY.value=eY.max; return;} // prevent out of bounds
obj.seg.startY = startY; obj.seg.startY = startY;
obj.seg.stopY = (cfg.comp.seglen?startY:0)+stopY; obj.seg.stopY = stopY;
} }
if (gId(`seg${s}grp`)) { // advanced options, not present in new segment dialog (makeSeg()) let g = gId(`seg${s}grp`);
var grp = parseInt(gId(`seg${s}grp`).value); if (g) { // advanced options, not present in new segment dialog (makeSeg())
var spc = parseInt(gId(`seg${s}spc`).value); let grp = parseInt(g.value);
var ofs = parseInt(gId(`seg${s}of` ).value); let spc = parseInt(gId(`seg${s}spc`).value);
let ofs = parseInt(gId(`seg${s}of` ).value);
obj.seg.grp = grp; obj.seg.grp = grp;
obj.seg.spc = spc; obj.seg.spc = spc;
obj.seg.of = ofs; obj.seg.of = ofs;

View File

@@ -7,7 +7,7 @@
<title>2D Set-up</title> <title>2D Set-up</title>
<script> <script>
var d=document; var d=document;
var loc = false, locip; var loc = false, locip;
var maxPanels=64; var maxPanels=64;
var ctx = null; // WLEDMM var ctx = null; // WLEDMM
var ledIndex = 0; // WLEDMM var ledIndex = 0; // WLEDMM
@@ -38,15 +38,15 @@
}); });
} }
function S() { function S() {
if (window.location.protocol == "file:") { if (window.location.protocol == "file:") {
loc = true; loc = true;
locip = localStorage.getItem('locIp'); locip = localStorage.getItem('locIp');
if (!locip) { if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!"); locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip); localStorage.setItem('locIp', locip);
} }
} }
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10'; var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
} }
@@ -91,12 +91,12 @@ Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0" oni
p.insertAdjacentHTML("beforeend", b); p.insertAdjacentHTML("beforeend", b);
} }
function remPanel() { function remPanel() {
let p = gId("panels").children; let p = gId("panels").children;
var i = p.length; var i = p.length;
if (i <= 1) return; if (i <= 1) return;
p[i-1].remove(); p[i-1].remove();
} }
function resetPanels() { function resetPanels() {
d.Sf.MPC.value = 1; d.Sf.MPC.value = 1;
@@ -350,7 +350,7 @@ Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0" oni
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr> <button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
</div> </div>
<h2>2D setup</h2> <h2>2D setup</h2>
Strip or panel: Strip or panel:
<select id="somp" name="SOMP" onchange="resetPanels();addPanels();UI();" > <select id="somp" name="SOMP" onchange="resetPanels();addPanels();UI();" >
<option value="0">1D Strip</option> <option value="0">1D Strip</option>
<option value="1">2D Matrix</option> <option value="1">2D Matrix</option>

View File

@@ -1,72 +1,72 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=500"> <meta name="viewport" content="width=500">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>DMX Settings</title> <title>DMX Settings</title>
<script> <script>
var d=document; var d=document;
var loc = false, locip; var loc = false, locip;
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");} function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
function B(){window.history.back();} function B(){window.history.back();}
function GCH(num) { function GCH(num) {
d.getElementById('dmxchannels').innerHTML += ""; d.getElementById('dmxchannels').innerHTML += "";
for (i=0;i<num;i++) { for (i=0;i<num;i++) {
d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n"; d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n";
} }
} }
function mMap(){ function mMap(){
numCh=document.Sf.CN.value; numCh=document.Sf.CN.value;
numGap=document.Sf.CG.value; numGap=document.Sf.CG.value;
if (parseInt(numCh)>parseInt(numGap)) { if (parseInt(numCh)>parseInt(numGap)) {
d.getElementById("gapwarning").style.display="block"; d.getElementById("gapwarning").style.display="block";
} else { } else {
d.getElementById("gapwarning").style.display="none"; d.getElementById("gapwarning").style.display="none";
} }
for (i=0;i<15;i++) { for (i=0;i<15;i++) {
if (i>=numCh) { if (i>=numCh) {
d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5"; d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5";
d.getElementById("CH"+(i+1)).disabled = true; d.getElementById("CH"+(i+1)).disabled = true;
} else { } else {
d.getElementById("CH"+(i+1) + "s").style.opacity = "1"; d.getElementById("CH"+(i+1) + "s").style.opacity = "1";
d.getElementById("CH"+(i+1)).disabled = false; d.getElementById("CH"+(i+1)).disabled = false;
} }
} }
} }
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
function loadJS(FILE_URL, async = true) { function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script"); let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL); scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript"); scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async); scE.setAttribute("async", async);
d.body.appendChild(scE); d.body.appendChild(scE);
// success event // success event
scE.addEventListener("load", () => { scE.addEventListener("load", () => {
//console.log("File loaded"); //console.log("File loaded");
GCH(15);GetV();mMap(); GCH(15);GetV();mMap();
}); });
// error event // error event
scE.addEventListener("error", (ev) => { scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev); console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!"); alert("Loading of configuration script failed.\nIncomplete page data!");
}); });
} }
function S(){ function S(){
if (window.location.protocol == "file:") { if (window.location.protocol == "file:") {
loc = true; loc = true;
locip = localStorage.getItem('locIp'); locip = localStorage.getItem('locIp');
if (!locip) { if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!"); locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip); localStorage.setItem('locIp', locip);
} }
} }
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=7'; var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=7';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
} }
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>
<body onload="S()"> <body onload="S()">
<form id="form_s" name="Sf" method="post"> <form id="form_s" name="Sf" method="post">

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@
<form id="form_s" name="Sf" method="post"> <form id="form_s" name="Sf" method="post">
<h2>Please enter settings PIN code</h2> <h2>Please enter settings PIN code</h2>
<input type="password" name="PIN" size="4" maxlength="4" minlength="4" pattern="[0-9]*" inputmode="numeric" autofocus> <input type="password" name="PIN" size="4" maxlength="4" minlength="4" pattern="[0-9]*" inputmode="numeric" autofocus>
<hr> <hr>
<button type="button" onclick="B()">Back</button><button type="submit">Submit</button> <button type="button" onclick="B()">Back</button><button type="submit">Submit</button>
</form> </form>
</body> </body>

View File

@@ -53,7 +53,7 @@
req.send(formData); req.send(formData);
fO.value = ''; fO.value = '';
return false; return false;
} }
function checkNum(o) { function checkNum(o) {
const specialkeys = ["Backspace", "Tab", "Enter", "Shift", "Control", "Alt", "Pause", "CapsLock", "Escape", "Space", "PageUp", "PageDown", "End", "Home", "ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown", "Insert", "Delete"]; const specialkeys = ["Backspace", "Tab", "Enter", "Shift", "Control", "Alt", "Pause", "CapsLock", "Escape", "Space", "PageUp", "PageDown", "End", "Home", "ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown", "Insert", "Delete"];
// true if key is a number or a special key // true if key is a number or a special key

View File

@@ -1,76 +1,76 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=500"> <meta name="viewport" content="width=500">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Sync Settings</title> <title>Sync Settings</title>
<script>var d=document; <script>var d=document;
var loc = false, locip; var loc = false, locip;
function gId(s){return d.getElementById(s);} function gId(s){return d.getElementById(s);}
function toggle(el){gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide");} function toggle(el){gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide");}
function hideNoDMX(){gId("dmxOnOff2").style.display="none";} function hideNoDMX(){gId("dmxOnOff2").style.display="none";} //WLEDMM
function hideNoLOX(){gId("loxOnOff2").style.display="none";} function hideNoLOX(){gId("loxOnOff2").style.display="none";} //WLEDMM
function H(){window.open("https://mm.kno.wled.ge/interfaces/udp-notifier/");} function H(){window.open("https://mm.kno.wled.ge/interfaces/udp-notifier/");}
function B(){window.open("/settings","_self");} function B(){window.open("/settings","_self");}
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;} function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} } else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
function loadJS(FILE_URL, async = true) { function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script"); let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL); scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript"); scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async); scE.setAttribute("async", async);
d.body.appendChild(scE); d.body.appendChild(scE);
// success event // success event
scE.addEventListener("load", () => { scE.addEventListener("load", () => {
//console.log("File loaded"); //console.log("File loaded");
GetV();SetVal(); GetV();SetVal();
}); });
// error event // error event
scE.addEventListener("error", (ev) => { scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev); console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!"); alert("Loading of configuration script failed.\nIncomplete page data!");
}); });
} }
function FC() function FC()
{ {
for(j=0;j<8;j++) for(j=0;j<8;j++)
{ {
gId("G"+(j+1)).checked=gId("GS").value>>j&1; gId("G"+(j+1)).checked=gId("GS").value>>j&1;
gId("R"+(j+1)).checked=gId("GR").value>>j&1; gId("R"+(j+1)).checked=gId("GR").value>>j&1;
} }
} }
function GC() function GC()
{ {
var a=0, b=0; var a=0, b=0;
var m=1; var m=1;
for(j=0;j<8;j++) for(j=0;j<8;j++)
{ {
a+=gId("G"+(j+1)).checked*m; a+=gId("G"+(j+1)).checked*m;
b+=gId("R"+(j+1)).checked*m; b+=gId("R"+(j+1)).checked*m;
m*=2; m*=2;
} }
gId("GS").value=a; gId("GS").value=a;
gId("GR").value=b; gId("GR").value=b;
} }
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;} function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();} function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();}
function S(){ function S(){
if (window.location.protocol == "file:") { if (window.location.protocol == "file:") {
loc = true; loc = true;
locip = localStorage.getItem('locIp'); locip = localStorage.getItem('locIp');
if (!locip) { if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!"); locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip); localStorage.setItem('locIp', locip);
}
} }
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=4'; }
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=4';
} loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
</script> }
<style>@import url("style.css");</style> </script>
<style>@import url("style.css");</style>
</head> </head>
<body onload="S()"> <body onload="S()">
<form id="form_s" name="Sf" method="post" onsubmit="GC()"> <form id="form_s" name="Sf" method="post" onsubmit="GC()">
@@ -86,39 +86,39 @@ UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required
<input name="GS" id="GS" type="number" style="display: none;"><!-- hidden inputs for bitwise group checkboxes --> <input name="GS" id="GS" type="number" style="display: none;"><!-- hidden inputs for bitwise group checkboxes -->
<input name="GR" id="GR" type="number" style="display: none;"> <input name="GR" id="GR" type="number" style="display: none;">
<table style="margin: 0 auto;"> <table style="margin: 0 auto;">
<tr> <tr>
<td></td> <td></td>
<td>1</td> <td>1</td>
<td>2</td> <td>2</td>
<td>3</td> <td>3</td>
<td>4</td> <td>4</td>
<td>5</td> <td>5</td>
<td>6</td> <td>6</td>
<td>7</td> <td>7</td>
<td>8</td> <td>8</td>
</tr> </tr>
<tr> <tr>
<td>Send:</td> <td>Send:</td>
<td><input type="checkbox" id="G1" name="G1"></td> <td><input type="checkbox" id="G1" name="G1"></td>
<td><input type="checkbox" id="G2" name="G2"></td> <td><input type="checkbox" id="G2" name="G2"></td>
<td><input type="checkbox" id="G3" name="G3"></td> <td><input type="checkbox" id="G3" name="G3"></td>
<td><input type="checkbox" id="G4" name="G4"></td> <td><input type="checkbox" id="G4" name="G4"></td>
<td><input type="checkbox" id="G5" name="G5"></td> <td><input type="checkbox" id="G5" name="G5"></td>
<td><input type="checkbox" id="G6" name="G6"></td> <td><input type="checkbox" id="G6" name="G6"></td>
<td><input type="checkbox" id="G7" name="G7"></td> <td><input type="checkbox" id="G7" name="G7"></td>
<td><input type="checkbox" id="G8" name="G8"></td> <td><input type="checkbox" id="G8" name="G8"></td>
</tr> </tr>
<tr> <tr>
<td>Receive:</td> <td>Receive:</td>
<td><input type="checkbox" id="R1" name="R1"></td> <td><input type="checkbox" id="R1" name="R1"></td>
<td><input type="checkbox" id="R2" name="R2"></td> <td><input type="checkbox" id="R2" name="R2"></td>
<td><input type="checkbox" id="R3" name="R3"></td> <td><input type="checkbox" id="R3" name="R3"></td>
<td><input type="checkbox" id="R4" name="R4"></td> <td><input type="checkbox" id="R4" name="R4"></td>
<td><input type="checkbox" id="R5" name="R5"></td> <td><input type="checkbox" id="R5" name="R5"></td>
<td><input type="checkbox" id="R6" name="R6"></td> <td><input type="checkbox" id="R6" name="R6"></td>
<td><input type="checkbox" id="R7" name="R7"></td> <td><input type="checkbox" id="R7" name="R7"></td>
<td><input type="checkbox" id="R8" name="R8"></td> <td><input type="checkbox" id="R8" name="R8"></td>
</tr> </tr>
</table><br> </table><br>
Receive: <nowrap><input type="checkbox" name="RB">Brightness,</nowrap> <nowrap><input type="checkbox" name="RC">Color,</nowrap> <nowrap>and <input type="checkbox" name="RX">Effects</nowrap><br> Receive: <nowrap><input type="checkbox" name="RB">Brightness,</nowrap> <nowrap><input type="checkbox" name="RC">Color,</nowrap> <nowrap>and <input type="checkbox" name="RX">Effects</nowrap><br>
<input type="checkbox" name="SO"> Segment options, <input type="checkbox" name="SG"> bounds<br> <input type="checkbox" name="SO"> Segment options, <input type="checkbox" name="SG"> bounds<br>
@@ -170,13 +170,13 @@ Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
Force max brightness: <input type="checkbox" name="FB"><br> Force max brightness: <input type="checkbox" name="FB"><br>
Disable realtime gamma correction: <input type="checkbox" name="RG"><br> Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required> Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
<div id="dmxOnOff2"> <div id="dmxOnOff2"> <!--WLEDMM-->
<br><em style="color:darkorange">This firmware build does not include DMX output support. <br></em> <br><em style="color:darkorange">This firmware build does not include DMX output support. <br></em>
</div> </div>
<hr class="sml"> <hr class="sml">
<h3>Alexa Voice Assistant</h3> <h3>Alexa Voice Assistant</h3>
<div id="NoAlexa" class="hide"> <div id="NoAlexa" class="hide">
<em style="color:#fa0;">This firmware build does not include Alexa support.<br></em><br> <em style="color:#fa0;">This firmware build does not include Alexa support.<br></em><br>
</div> </div>
<div id="Alexa"> <div id="Alexa">
Emulate Alexa device: <input type="checkbox" name="AL"><br> Emulate Alexa device: <input type="checkbox" name="AL"><br>
@@ -192,7 +192,7 @@ For best results, only use one of these services at a time.<br>
<hr class="sml"> <hr class="sml">
<h3>Blynk</h3> <h3>Blynk</h3>
<div id="NoBlynk" class="hide"> <div id="NoBlynk" class="hide">
<em style="color:#fa0;">This firmware build does not include Blynk support.<br></em> <em style="color:#fa0;">This firmware build does not include Blynk support.<br></em>
</div> </div>
<div id="Blynk"> <div id="Blynk">
Host: <input type="text" name="BH" maxlength="32"> Host: <input type="text" name="BH" maxlength="32">
@@ -202,7 +202,7 @@ Device Auth token: <input name="BK" maxlength="33"><br>
</div> </div>
<h3>MQTT</h3> <h3>MQTT</h3>
<div id="NoMQTT" class="hide"> <div id="NoMQTT" class="hide">
<em style="color:#fa0;">This firmware build does not include MQTT support.<br></em> <em style="color:#fa0;">This firmware build does not include MQTT support.<br></em>
</div> </div>
<div id="MQTT"> <div id="MQTT">
Enable MQTT: <input type="checkbox" name="MQ"><br> Enable MQTT: <input type="checkbox" name="MQ"><br>
@@ -220,7 +220,7 @@ Publish on button press: <input type="checkbox" name="BM"><br>
</div> </div>
<h3>Philips Hue</h3> <h3>Philips Hue</h3>
<div id="NoHue" class="hide"> <div id="NoHue" class="hide">
<em style="color:#fa0;">This firmware build does not include Philips Hue support.<br></em> <em style="color:#fa0;">This firmware build does not include Philips Hue support.<br></em>
</div> </div>
<div id="Hue"> <div id="Hue">
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br> <i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
@@ -235,7 +235,7 @@ Hue Bridge IP:<br>
(when first connecting)<br> (when first connecting)<br>
</div> </div>
Hue status: <span class="sip"> Disabled in this build </span> Hue status: <span class="sip"> Disabled in this build </span>
<div id="loxOnOff2"> <div id="loxOnOff2"> <!--WLEDMM-->>
<br><em style="color:darkorange">This firmware build does not include Loxone Lighting support. <br></em> <br><em style="color:darkorange">This firmware build does not include Loxone Lighting support. <br></em>
</div> </div>
<h3>Serial</h3> <h3>Serial</h3>

View File

@@ -6,8 +6,8 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>Time Settings</title> <title>Time Settings</title>
<script> <script>
var d=document; var d=document;
var loc = false, locip; var loc = false, locip;
var el=false; var el=false;
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
function H() { window.open("https://mm.kno.wled.ge/features/settings/#time-settings"); } function H() { window.open("https://mm.kno.wled.ge/features/settings/#time-settings"); }
@@ -156,7 +156,7 @@
</div> </div>
<h2>Time setup</h2> <h2>Time setup</h2>
Get time from NTP server: <input type="checkbox" name="NT"><br> Get time from NTP server: <input type="checkbox" name="NT"><br>
<input type="text" name="NS" maxlength="32"><br> <input type="text" name="NS" maxlength="32"><br>
Use 24h format: <input type="checkbox" name="CF"><br> Use 24h format: <input type="checkbox" name="CF"><br>
Time zone: Time zone:
<select name="TZ"> <select name="TZ">

View File

@@ -6,234 +6,234 @@
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>UI Settings</title> <title>UI Settings</title>
<script> <script>
var d = document; var d = document;
var loc = false, locip; var loc = false, locip;
var initial_ds, initial_st, initial_su; var initial_ds, initial_st, initial_su;
var sett = null; var sett = null;
var l = { var l = {
"comp":{ "comp":{
"labels":"Show button labels", "labels":"Show button labels",
"colors":{ "colors":{
"LABEL":"Color selection methods", "LABEL":"Color selection methods",
"picker": "Color Wheel", "picker": "Color Wheel",
"rgb": "RGB sliders", "rgb": "RGB sliders",
"quick": "Quick color selectors", "quick": "Quick color selectors",
"hex": "HEX color input" "hex": "HEX color input"
}, },
"pcmbot": "Show bottom tab bar in PC mode", "pcmbot": "Show bottom tab bar in PC mode",
"pid": "Show preset IDs", "pid": "Show preset IDs",
"seglen": "Set segment length instead of stop LED", "seglen": "Set segment length instead of stop LED",
"segpwr": "Hide segment power &amp; brightness", "segpwr": "Hide segment power &amp; brightness",
"segexp" : "Always expand first segment", "segexp" : "Always expand first segment",
"css": "Enable custom CSS", "css": "Enable custom CSS",
"hdays": "Enable custom Holidays list" "hdays": "Enable custom Holidays list"
},
"theme":{
"alpha": {
"bg":"Background opacity",
"tab":"Button opacity"
}, },
"theme":{ "bg":{
"alpha": { "url":"BG image URL",
"bg":"Background opacity", "random":"Random BG image"
"tab":"Button opacity" },
}, "color":{
"bg":{ "bg":"BG HEX color"
"url":"BG image URL",
"random":"Random BG image"
},
"color":{
"bg":"BG HEX color"
}
} }
};
function gId(s) { return d.getElementById(s); }
function toggle(el) { gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide"); }
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
} }
function set(path, obj, val) { };
var tar = obj; function gId(s) { return d.getElementById(s); }
var pList = path.split('_'); function toggle(el) { gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide"); }
var len = pList.length; function isObject(item) {
for(var i = 0; i < len-1; i++) { return (item && typeof item === 'object' && !Array.isArray(item));
var elem = pList[i]; }
if( !tar[elem] ) tar[elem] = {} function set(path, obj, val) {
tar = tar[elem]; var tar = obj;
} var pList = path.split('_');
tar[pList[len-1]] = val; var len = pList.length;
for(var i = 0; i < len-1; i++) {
var elem = pList[i];
if( !tar[elem] ) tar[elem] = {}
tar = tar[elem];
} }
var timeout; tar[pList[len-1]] = val;
function showToast(text, error = false) }
var timeout;
function showToast(text, error = false)
{
var x = gId("toast");
x.innerHTML = text;
x.classList.add(error ? "error":"show");
clearTimeout(timeout);
x.style.animation = 'none';
timeout = setTimeout(function(){ x.classList.remove("show"); }, 2900);
}
function addRec(s, path = "", label = null)
{
var str = "";
for (i in s)
{ {
var x = gId("toast"); var fk = path + (path?'_':'') + i;
x.innerHTML = text; if (isObject(s[i])) {
x.classList.add(error ? "error":"show"); if (label && label[i] && label[i]["LABEL"]) str += `<h3>${label[i]["LABEL"]}</h3>`;
clearTimeout(timeout); str += addRec(s[i], fk, label? label[i] : null);
x.style.animation = 'none'; } else {
timeout = setTimeout(function(){ x.classList.remove("show"); }, 2900); var lb = fk;
} if (label && label[i]) lb = label[i];
function addRec(s, path = "", label = null) else if (s[i+'LABEL']) lb = s[i+'LABEL'];
{ if (i.indexOf('LABEL') > 0) continue;
var str = ""; var t = typeof s[i];
for (i in s) if (gId(fk)) { //already exists
{ if(t === 'boolean')
var fk = path + (path?'_':'') + i; {
if (isObject(s[i])) { gId(fk).checked = s[i];
if (label && label[i] && label[i]["LABEL"]) str += `<h3>${label[i]["LABEL"]}</h3>`;
str += addRec(s[i], fk, label? label[i] : null);
} else {
var lb = fk;
if (label && label[i]) lb = label[i];
else if (s[i+'LABEL']) lb = s[i+'LABEL'];
if (i.indexOf('LABEL') > 0) continue;
var t = typeof s[i];
if (gId(fk)) { //already exists
if(t === 'boolean')
{
gId(fk).checked = s[i];
} else {
gId(fk).value = s[i];
}
if (gId(fk).previousElementSibling.matches('.l')) {
gId(fk).previousElementSibling.innerHTML = lb;
}
} else { } else {
if(t === 'boolean') gId(fk).value = s[i];
{ }
str += `${lb}: <input class="agi cb" type="checkbox" id=${fk} ${s[i]?"checked":""}><br>`; if (gId(fk).previousElementSibling.matches('.l')) {
} else if (t === 'number') gId(fk).previousElementSibling.innerHTML = lb;
{ }
str += `${lb}: <input class="agi" type="number" id=${fk} value=${s[i]}><br>`; } else {
} else if (t === 'string') if(t === 'boolean')
{ {
str += `${lb}:<br><input class="agi" id=${fk} value=${s[i]}><br>`; str += `${lb}: <input class="agi cb" type="checkbox" id=${fk} ${s[i]?"checked":""}><br>`;
} } else if (t === 'number')
{
str += `${lb}: <input class="agi" type="number" id=${fk} value=${s[i]}><br>`;
} else if (t === 'string')
{
str += `${lb}:<br><input class="agi" id=${fk} value=${s[i]}><br>`;
} }
} }
} }
return str;
} }
return str;
}
function genForm(s) { function genForm(s) {
var str = ""; var str = "";
str = addRec(s,"",l); str = addRec(s,"",l);
gId('gen').innerHTML = str; gId('gen').innerHTML = str;
}
function GetLS()
{
sett = localStorage.getItem('wledUiCfg');
if (!sett) gId('lserr').style.display = "inline";
try {
sett = JSON.parse(sett);
} catch (e) {
sett = {};
gId('lserr').style.display = "inline";
gId('lserr').innerHTML = "&#9888; Settings JSON parsing failed. (" + e + ")";
} }
function GetLS() genForm(sett);
{ gId('dm').checked = (gId('theme_base').value === 'light');
sett = localStorage.getItem('wledUiCfg'); }
if (!sett) gId('lserr').style.display = "inline";
try { function SetLS()
sett = JSON.parse(sett); {
} catch (e) { var l = d.querySelectorAll('.agi');
sett = {}; for (var i = 0; i < l.length; i++) {
gId('lserr').style.display = "inline"; var e = l[i];
gId('lserr').innerHTML = "&#9888; Settings JSON parsing failed. (" + e + ")"; var val = e.classList.contains('cb') ? e.checked : e.value;
} set(e.id, sett, val);
genForm(sett); console.log(`${e.id} set to ${val}`);
gId('dm').checked = (gId('theme_base').value === 'light');
} }
try {
localStorage.setItem('wledUiCfg', JSON.stringify(sett));
gId('lssuc').style.display = "inline";
} catch (e) {
gId('lssuc').style.display = "none";
gId('lserr').style.display = "inline";
gId('lserr').innerHTML = "&#9888; Settings JSON saving failed. (" + e + ")";
}
}
function cLS()
{
localStorage.removeItem('wledP');
localStorage.removeItem('wledPmt');
localStorage.removeItem('wledPalx');
showToast("Cleared.");
}
function SetLS() function Save() {
{ SetLS();
var l = d.querySelectorAll('.agi'); if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st || d.Sf.SU.checked != initial_su) d.Sf.submit();
for (var i = 0; i < l.length; i++) { }
var e = l[i];
var val = e.classList.contains('cb') ? e.checked : e.value; // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
set(e.id, sett, val); function loadJS(FILE_URL, async = true) {
console.log(`${e.id} set to ${val}`); let scE = d.createElement("script");
} scE.setAttribute("src", FILE_URL);
try { scE.setAttribute("type", "text/javascript");
localStorage.setItem('wledUiCfg', JSON.stringify(sett)); scE.setAttribute("async", async);
gId('lssuc').style.display = "inline"; d.body.appendChild(scE);
} catch (e) { // success event
gId('lssuc').style.display = "none"; scE.addEventListener("load", () => {
gId('lserr').style.display = "inline"; //console.log("File loaded");
gId('lserr').innerHTML = "&#9888; Settings JSON saving failed. (" + e + ")"; GetV();
initial_ds = d.Sf.DS.value;
initial_st = d.Sf.ST.checked;
initial_su = d.Sf.SU.checked;
GetLS();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
}
function S()
{
if (window.location.protocol == "file:") {
loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
} }
} }
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=3';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
}
function H() { window.open("https://mm.kno.wled.ge/features/settings/#user-interface-settings"); }
function B() { window.open("/settings","_self"); }
function UI()
{
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
var f = gId('theme_base');
if (f) f.value = (gId('dm').checked) ? 'light':'dark';
}
function cLS() // random BG image
{ function setRandomBg() {
localStorage.removeItem('wledP'); if (gId("theme_bg_random").checked) {
localStorage.removeItem('wledPmt'); gId("theme_bg_url").value = "https://picsum.photos/1920/1080";
localStorage.removeItem('wledPalx'); } else {
showToast("Cleared."); gId("theme_bg_url").value = "";
} }
function Save() { }
SetLS(); function checkRandomBg() {
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st || d.Sf.SU.checked != initial_su) d.Sf.submit(); if (gId("theme_bg_url").value === "https://picsum.photos/1920/1080") {
} gId("theme_bg_random").checked = true;
} else {
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript gId("theme_bg_random").checked = false;
function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
GetV();
initial_ds = d.Sf.DS.value;
initial_st = d.Sf.ST.checked;
initial_su = d.Sf.SU.checked;
GetLS();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
}
function S()
{
if (window.location.protocol == "file:") {
loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
}
}
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=3';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
}
function H() { window.open("https://mm.kno.wled.ge/features/settings/#user-interface-settings"); }
function B() { window.open("/settings","_self"); }
function UI()
{
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
var f = gId('theme_base');
if (f) f.value = (gId('dm').checked) ? 'light':'dark';
}
// random BG image
function setRandomBg() {
if (gId("theme_bg_random").checked) {
gId("theme_bg_url").value = "https://picsum.photos/1920/1080";
} else {
gId("theme_bg_url").value = "";
}
}
function checkRandomBg() {
if (gId("theme_bg_url").value === "https://picsum.photos/1920/1080") {
gId("theme_bg_random").checked = true;
} else {
gId("theme_bg_random").checked = false;
}
}
function uploadFile(fO,name) {
var req = new XMLHttpRequest();
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
req.addEventListener('error', function(e){showToast(e.stack,true);});
req.open("POST", "/upload");
var formData = new FormData();
formData.append("data", fO.files[0], name);
req.send(formData);
fO.value = '';
return false;
} }
}
function uploadFile(fO,name) {
var req = new XMLHttpRequest();
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
req.addEventListener('error', function(e){showToast(e.stack,true);});
req.open("POST", "/upload");
var formData = new FormData();
formData.append("data", fO.files[0], name);
req.send(formData);
fO.value = '';
return false;
}
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>

View File

@@ -264,19 +264,20 @@ class Usermod {
virtual ~Usermod() { if (um_data) delete um_data; } virtual ~Usermod() { if (um_data) delete um_data; }
virtual void setup() = 0; // pure virtual, has to be overriden virtual void setup() = 0; // pure virtual, has to be overriden
virtual void loop() = 0; // pure virtual, has to be overriden virtual void loop() = 0; // pure virtual, has to be overriden
virtual void handleOverlayDraw() {} virtual void handleOverlayDraw() {} // called after all effects have been processed, just before strip.show()
virtual bool handleButton(uint8_t b) { return false; } virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here
virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects]
virtual void connected() {} virtual void connected() {} // called when WiFi is (re)connected
virtual void appendConfigData() {} virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields
virtual void addToJsonState(JsonObject& obj) {} virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state
virtual void addToJsonInfo(JsonObject& obj) {} virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page
virtual void readFromJsonState(JsonObject& obj) {} virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server
virtual void addToConfig(JsonObject& obj) {} virtual void addToConfig(JsonObject& obj) {} // add JSON entries that go to cfg.json
virtual bool readFromConfig(JsonObject& obj) { return true; } // Note as of 2021-06 readFromConfig() now needs to return a bool, see usermod_v2_example.h virtual bool readFromConfig(JsonObject& obj) { return true; } // Note as of 2021-06 readFromConfig() now needs to return a bool, see usermod_v2_example.h
virtual void onMqttConnect(bool sessionPresent) {} virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe)
virtual bool onMqttMessage(char* topic, char* payload) { return false; } virtual bool onMqttMessage(char* topic, char* payload) { return false; } // fired upon MQTT message received (wled topic)
virtual void onUpdateBegin(bool) {} virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update
virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;} virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
}; };
@@ -301,6 +302,7 @@ class UsermodManager {
void onMqttConnect(bool sessionPresent); void onMqttConnect(bool sessionPresent);
bool onMqttMessage(char* topic, char* payload); bool onMqttMessage(char* topic, char* payload);
void onUpdateBegin(bool); void onUpdateBegin(bool);
void onStateChange(uint8_t);
bool add(Usermod* um); bool add(Usermod* um);
Usermod* lookup(uint16_t mod_id); Usermod* lookup(uint16_t mod_id);
Usermod* lookupName(const char *mod_name); //WLEDMM Usermod* lookupName(const char *mod_name); //WLEDMM

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -273,6 +273,9 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
JsonArray iarr = elem[F("i")]; //set individual LEDs JsonArray iarr = elem[F("i")]; //set individual LEDs
if (!iarr.isNull()) { if (!iarr.isNull()) {
uint8_t oldMap1D2D = seg.map1D2D;
seg.map1D2D = M12_Pixels; // no mapping
// set brightness immediately and disable transition // set brightness immediately and disable transition
transitionDelayTemp = 0; transitionDelayTemp = 0;
jsonTransitionOnce = true; jsonTransitionOnce = true;
@@ -316,6 +319,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
set = 0; set = 0;
} }
} }
seg.map1D2D = oldMap1D2D; // restore mapping
strip.trigger(); // force segment update strip.trigger(); // force segment update
} }
// send UDP/WS if segment options changed (except selection; will also deselect current preset) // send UDP/WS if segment options changed (except selection; will also deselect current preset)

View File

@@ -129,6 +129,9 @@ void stateUpdated(byte callMode) {
//deactivate nightlight if target brightness is reached //deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false; if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
// notify usermods of state change
usermods.onStateChange(callMode);
if (fadeTransition) { if (fadeTransition) {
//set correct delay if not using notification delay //set correct delay if not using notification delay
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay; // load actual transition duration if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay; // load actual transition duration

View File

@@ -15,6 +15,7 @@ class NetworkDebugPrinter : public Print {
virtual void flush( bool txOnly) { return;} // WLEDMM virtual void flush( bool txOnly) { return;} // WLEDMM
}; };
// use it on your linux/macOS with: nc -p 7868 -u -l -s <network ip>
extern NetworkDebugPrinter NetDebug; extern NetworkDebugPrinter NetDebug;
#endif #endif

View File

@@ -156,7 +156,7 @@ void serializePlaylist(JsonObject sObj) {
JsonArray ps = playlist.createNestedArray("ps"); JsonArray ps = playlist.createNestedArray("ps");
JsonArray dur = playlist.createNestedArray("dur"); JsonArray dur = playlist.createNestedArray("dur");
JsonArray transition = playlist.createNestedArray(F("transition")); JsonArray transition = playlist.createNestedArray(F("transition"));
playlist[F("repeat")] = playlistRepeat; playlist[F("repeat")] = (playlistIndex < 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running)
playlist["end"] = playlistEndPreset; playlist["end"] = playlistEndPreset;
playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE; playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE;
for (int i=0; i<playlistLen; i++) { for (int i=0; i<playlistLen; i++) {

View File

@@ -274,7 +274,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
} else { } else {
// this is a playlist or API call // this is a playlist or API call
if (sObj[F("playlist")].isNull()) { if (sObj[F("playlist")].isNull()) {
// we will save API call immediately // we will save API call immediately (often causes presets.json corruption)
presetToSave = 0; presetToSave = 0;
if (index > 250 || !fileDoc) return; // cannot save API calls to temporary preset (255) if (index > 250 || !fileDoc) return; // cannot save API calls to temporary preset (255)
sObj.remove("o"); sObj.remove("o");
@@ -284,11 +284,12 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
sObj.remove(F("psave")); sObj.remove(F("psave"));
if (sObj["n"].isNull()) sObj["n"] = saveName; if (sObj["n"].isNull()) sObj["n"] = saveName;
initPresetsFile(); // just in case if someone deleted presets.json using /edit initPresetsFile(); // just in case if someone deleted presets.json using /edit
writeObjectToFileUsingId(getFileName(index), index, fileDoc); writeObjectToFileUsingId(getFileName(index<255), index, fileDoc);
presetsModifiedTime = toki.second(); //unix time presetsModifiedTime = toki.second(); //unix time
updateFSInfo(); updateFSInfo();
} else { } else {
// store playlist // store playlist
// WARNING: playlist will be loaded in json.cpp after this call and will have repeat counter increased by 1
includeBri = true; // !sObj["on"].isNull(); includeBri = true; // !sObj["on"].isNull();
playlistSave = true; playlistSave = true;
} }

View File

@@ -40,6 +40,7 @@ bool UsermodManager::onMqttMessage(char* topic, char* payload) {
return false; return false;
} }
void UsermodManager::onUpdateBegin(bool init) { for (byte i = 0; i < numMods; i++) ums[i]->onUpdateBegin(init); } // notify usermods that update is to begin void UsermodManager::onUpdateBegin(bool init) { for (byte i = 0; i < numMods; i++) ums[i]->onUpdateBegin(init); } // notify usermods that update is to begin
void UsermodManager::onStateChange(uint8_t mode) { for (byte i = 0; i < numMods; i++) ums[i]->onStateChange(mode); } // notify usermods that WLED state changed
/* /*
* Enables usermods to lookup another Usermod. * Enables usermods to lookup another Usermod.

View File

@@ -96,10 +96,6 @@
#include "my_config.h" #include "my_config.h"
#endif #endif
#ifdef WLED_DEBUG_HOST
#include "net_debug.h"
#endif
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#ifdef WLED_ADD_EEPROM_SUPPORT #ifdef WLED_ADD_EEPROM_SUPPORT
#include <EEPROM.h> #include <EEPROM.h>
@@ -730,6 +726,7 @@ WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0);
// enable additional debug output // enable additional debug output
#if defined(WLED_DEBUG_HOST) #if defined(WLED_DEBUG_HOST)
#include "net_debug.h"
// On the host side, use netcat to receive the log statements: nc -l 7868 -u // On the host side, use netcat to receive the log statements: nc -l 7868 -u
// use -D WLED_DEBUG_HOST='"192.168.xxx.xxx"' or FQDN within quotes // use -D WLED_DEBUG_HOST='"192.168.xxx.xxx"' or FQDN within quotes
#define DEBUGOUT NetDebug #define DEBUGOUT NetDebug