Merge branch '0_15' into suspend

This commit is contained in:
Blaz Kristan 2024-01-04 17:33:07 +01:00
commit fc6e7c81d3
32 changed files with 1194 additions and 1080 deletions

View File

@ -1,19 +1,37 @@
## WLED changelog ## WLED changelog
#### Build 2309120 till build 2311120 #### Build 2309120 till build 2312290
- WLED version 0.15.0-a0 - WLED version 0.15.0-a0
- Per port Auto Brightness Limiter (ABL)
- Use PSRAM for JSON buffer (double size, larger ledmaps, up to 2k)
- Reduced heap fragmentation by allocating ledmap array only once and not deallocating effect buffer
- HTTP retries on failed UI load
- UI Search: scroll to top (#3587 by @WoodyLetsCode)
- Return to inline iro.js and rangetouch.js (#3597 by @WoodyLetsCode)
- Better caching (#3591 by @WoodyLetsCode)
- Do not send 404 for missing `skin.css` (#3590 by @WoodyLetsCode)
- Simplified UI rework (#3511 by @WoodyLetsCode)
- Domoticz device ID for PIR and Temperature usermods
- Bugfix for UCS8904 `hasWhite()`
- Better search in UI (#3540 by @WoodyLetsCode)
- Seeding FastLED PRNG (#3552 by @TripleWhy)
- WIZ Smart Button support (#3547 by @micw)
- New button type (button switch, fix for #3537)
- Pixel Magic Tool update (#3483 by @ajotanc)
- Effect: 2D Matrix fix for gaps
- Bugfix #3526, #3533, #3561
- Spookier Halloween Eyes (#3501) - Spookier Halloween Eyes (#3501)
- Compile time options for Multi Relay usermod (#3498) - Compile time options for Multi Relay usermod (#3498)
- Fix for Dissolve (#3502) - Effect: Fix for Dissolve (#3502)
- Better reverse proxy support (nested paths) - Better reverse proxy support (nested paths)
- Implement global JSON API boolean toggle (i.e. instead of "var":true or "var":false -> "var":"t"). - Implement global JSON API boolean toggle (i.e. instead of "var":true or "var":false -> "var":"t").
- Sort presets by ID - Sort presets by ID
- Fix #3496 - Fix for #3496, #2922, #3593, #3514, #3522, #3578 (partial), #3606 (@WoodyLetsCode)
- Improved random bg image and added random bg image options (@WoodyLetsCode, #3481) - Improved random bg image and added random bg image options (@WoodyLetsCode, #3481)
- Audio palettes (Audioreactive usermod, credit @netmindz) - Audio palettes (Audioreactive usermod, credit @netmindz)
- Better UI tooltips (@ajotnac, #3464) - Better UI tooltips (@ajotnac, #3464)
- Better effect filters (filter dropdown) - Better effect filters (filter dropdown)
- Fix udp sync (fix for #3487) - UDP sync fix (for #3487)
- Power button override (solves #3431) - Power button override (solves #3431)
- Additional HTTP request throttling (ESP8266) - Additional HTTP request throttling (ESP8266)
- Additional UI/UX improvements - Additional UI/UX improvements

View File

@ -307,7 +307,7 @@ class St7789DisplayUsermod : public Usermod {
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate). // Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
tft.print("Current: "); tft.print("Current: ");
tft.setTextColor(TFT_ORANGE); tft.setTextColor(TFT_ORANGE);
tft.print(strip.currentMilliamps); tft.print(BusManager::currentMilliamps());
tft.print("mA"); tft.print("mA");
} }

View File

@ -84,11 +84,11 @@ class QuinLEDAnPentaUsermod : public Usermod
void getCurrentUsedLedPins() void getCurrentUsedLedPins()
{ {
for (int8_t lp = 0; lp <= 4; lp++) currentLedPins[lp] = 0; for (int8_t lp = 0; lp <= 4; lp++) currentLedPins[lp] = 0;
byte numBusses = busses.getNumBusses(); byte numBusses = BusManager::getNumBusses();
byte numUsedPins = 0; byte numUsedPins = 0;
for (int8_t b = 0; b < numBusses; b++) { for (int8_t b = 0; b < numBusses; b++) {
Bus* curBus = busses.getBus(b); Bus* curBus = BusManager::getBus(b);
if (curBus != nullptr) { if (curBus != nullptr) {
uint8_t pins[5] = {0, 0, 0, 0, 0}; uint8_t pins[5] = {0, 0, 0, 0, 0};
currentBussesNumPins[b] = curBus->getPins(pins); currentBussesNumPins[b] = curBus->getPins(pins);
@ -104,11 +104,11 @@ class QuinLEDAnPentaUsermod : public Usermod
void getCurrentLedcValues() void getCurrentLedcValues()
{ {
byte numBusses = busses.getNumBusses(); byte numBusses = BusManager::getNumBusses();
byte numLedc = 0; byte numLedc = 0;
for (int8_t b = 0; b < numBusses; b++) { for (int8_t b = 0; b < numBusses; b++) {
Bus* curBus = busses.getBus(b); Bus* curBus = BusManager::getBus(b);
if (curBus != nullptr) { if (curBus != nullptr) {
uint32_t curPixColor = curBus->getPixelColor(0); uint32_t curPixColor = curBus->getPixelColor(0);
uint8_t _data[5] = {255, 255, 255, 255, 255}; uint8_t _data[5] = {255, 255, 255, 255, 255};

View File

@ -3444,8 +3444,8 @@ static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chanc
uint16_t mode_exploding_fireworks(void) uint16_t mode_exploding_fireworks(void)
{ {
if (SEGLEN == 1) return mode_static(); if (SEGLEN == 1) return mode_static();
const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1; const uint16_t cols = SEGMENT.is2D() ? SEGMENT.virtualWidth() : 1;
const uint16_t rows = strip.isMatrix ? SEGMENT.virtualHeight() : SEGMENT.virtualLength(); const uint16_t rows = SEGMENT.is2D() ? SEGMENT.virtualHeight() : SEGMENT.virtualLength();
//allocate segment data //allocate segment data
uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
@ -3476,11 +3476,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-3) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D flare->posX = SEGMENT.is2D() ? 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(9)-4)/32.f : 0; // no X velocity on 1D flare->velX = SEGMENT.is2D() ? (random8(9)-4)/64.0f : 0; // no X velocity on 1D
flare->col = 255; //brightness flare->col = 255; //brightness
SEGENV.aux0 = 1; SEGENV.aux0 = 1;
} }
@ -3488,12 +3488,14 @@ uint16_t mode_exploding_fireworks(void)
// launch // launch
if (flare->vel > 12 * gravity) { if (flare->vel > 12 * gravity) {
// flare // flare
if (strip.isMatrix) SEGMENT.setPixelColorXY(int(flare->posX), rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col); if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(flare->posX), rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col);
else SEGMENT.setPixelColor(int(flare->posX) ? rows - int(flare->pos) - 1 : int(flare->pos), flare->col, flare->col, flare->col); else SEGMENT.setPixelColor((flare->posX > 0.0f) ? rows - int(flare->pos) - 1 : int(flare->pos), flare->col, flare->col, flare->col);
flare->pos += flare->vel; flare->pos += flare->vel;
flare->posX += flare->velX;
flare->pos = constrain(flare->pos, 0, rows-1); flare->pos = constrain(flare->pos, 0, rows-1);
flare->posX = constrain(flare->posX, 0, cols-strip.isMatrix); if (SEGMENT.is2D()) {
flare->posX += flare->velX;
flare->posX = constrain(flare->posX, 0, cols-1);
}
flare->vel += gravity; flare->vel += gravity;
flare->col -= 2; flare->col -= 2;
} else { } else {
@ -3516,12 +3518,12 @@ uint16_t mode_exploding_fireworks(void)
sparks[i].posX = flare->posX; sparks[i].posX = flare->posX;
sparks[i].vel = (float(random16(20001)) / 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(10001)) / 10000.0f) - 0.5f : 0; // from -0.5 to 0.5 sparks[i].velX = SEGMENT.is2D() ? (float(random16(20001)) / 10000.0f) - 1.0f : 0; // from -1 to 1
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();
sparks[i].vel *= flare->pos/rows; // proportional to height sparks[i].vel *= flare->pos/rows; // proportional to height
sparks[i].velX *= strip.isMatrix ? flare->posX/cols : 0; // proportional to width sparks[i].velX *= SEGMENT.is2D() ? flare->posX/cols : 0; // proportional to width
sparks[i].vel *= -gravity *50; sparks[i].vel *= -gravity *50;
} }
//sparks[1].col = 345; // this will be our known spark //sparks[1].col = 345; // this will be our known spark
@ -3534,11 +3536,11 @@ uint16_t mode_exploding_fireworks(void)
sparks[i].pos += sparks[i].vel; sparks[i].pos += sparks[i].vel;
sparks[i].posX += sparks[i].velX; sparks[i].posX += sparks[i].velX;
sparks[i].vel += *dying_gravity; sparks[i].vel += *dying_gravity;
sparks[i].velX += strip.isMatrix ? *dying_gravity : 0; sparks[i].velX += SEGMENT.is2D() ? *dying_gravity : 0;
if (sparks[i].col > 3) sparks[i].col -= 4; if (sparks[i].col > 3) sparks[i].col -= 4;
if (sparks[i].pos > 0 && sparks[i].pos < rows) { if (sparks[i].pos > 0 && sparks[i].pos < rows) {
if (strip.isMatrix && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue; if (SEGMENT.is2D() && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue;
uint16_t prog = sparks[i].col; uint16_t prog = sparks[i].col;
uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0); uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0);
CRGB c = CRGB::Black; //HeatColor(sparks[i].col); CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
@ -3550,7 +3552,7 @@ uint16_t mode_exploding_fireworks(void)
c.g = qsub8(c.g, cooling); c.g = qsub8(c.g, cooling);
c.b = qsub8(c.b, cooling * 2); c.b = qsub8(c.b, cooling * 2);
} }
if (strip.isMatrix) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue); if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue);
else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c.red, c.green, c.blue); else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c.red, c.green, c.blue);
} }
} }

View File

@ -62,10 +62,10 @@
//#define FRAMETIME _frametime //#define FRAMETIME _frametime
#define FRAMETIME strip.getFrameTime() #define FRAMETIME strip.getFrameTime()
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#ifdef ESP8266 #ifdef ESP8266
#define MAX_NUM_SEGMENTS 16 #define MAX_NUM_SEGMENTS 12
/* How much data bytes all segments combined may allocate */ /* How much data bytes all segments combined may allocate */
#define MAX_SEGMENT_DATA 5120 #define MAX_SEGMENT_DATA 5120
#else #else
@ -73,9 +73,13 @@
#define MAX_NUM_SEGMENTS 32 #define MAX_NUM_SEGMENTS 32
#endif #endif
#if defined(ARDUINO_ARCH_ESP32S2) #if defined(ARDUINO_ARCH_ESP32S2)
#define MAX_SEGMENT_DATA 24576 #if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1024 // 32k by default
#else
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default
#endif
#else #else
#define MAX_SEGMENT_DATA 32767 #define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1280 // 40k by default
#endif #endif
#endif #endif
@ -682,10 +686,7 @@ class WS2812FX { // 96 bytes
WS2812FX() : WS2812FX() :
paletteFade(0), paletteFade(0),
paletteBlend(0), paletteBlend(0),
milliampsPerLed(55),
cctBlending(0), cctBlending(0),
ablMilliampsMax(ABL_MILLIAMPS_DEFAULT),
currentMilliamps(0),
now(millis()), now(millis()),
timebase(0), timebase(0),
isMatrix(false), isMatrix(false),
@ -797,7 +798,6 @@ class WS2812FX { // 96 bytes
uint8_t uint8_t
paletteBlend, paletteBlend,
milliampsPerLed,
cctBlending, cctBlending,
getActiveSegmentsNum(void), getActiveSegmentsNum(void),
getFirstSelectedSegId(void), getFirstSelectedSegId(void),
@ -815,8 +815,6 @@ class WS2812FX { // 96 bytes
inline uint8_t getModeCount() { return _modeCount; } inline uint8_t getModeCount() { return _modeCount; }
uint16_t uint16_t
ablMilliampsMax,
currentMilliamps,
getLengthPhysical(void), getLengthPhysical(void),
getLengthTotal(void), // will include virtual/nonexistent pixels in matrix getLengthTotal(void), // will include virtual/nonexistent pixels in matrix
getFps(); getFps();

View File

@ -91,12 +91,12 @@ void WS2812FX::setUpMatrix() {
DEBUG_PRINT(F("Reading LED gap from ")); DEBUG_PRINT(F("Reading LED gap from "));
DEBUG_PRINTLN(fileName); DEBUG_PRINTLN(fileName);
// read the array into global JSON buffer // read the array into global JSON buffer
if (readObjectFromFile(fileName, nullptr, &doc)) { if (readObjectFromFile(fileName, nullptr, pDoc)) {
// the array is similar to ledmap, except it has only 3 values: // the array is similar to ledmap, except it has only 3 values:
// -1 ... missing pixel (do not increase pixel count) // -1 ... missing pixel (do not increase pixel count)
// 0 ... inactive pixel (it does count, but should be mapped out (-1)) // 0 ... inactive pixel (it does count, but should be mapped out (-1))
// 1 ... active pixel (it will count and will be mapped) // 1 ... active pixel (it will count and will be mapped)
JsonArray map = doc.as<JsonArray>(); JsonArray map = pDoc->as<JsonArray>();
gapSize = map.size(); gapSize = map.size();
if (!map.isNull() && gapSize >= matrixSize) { // not an empty map if (!map.isNull() && gapSize >= matrixSize) { // not an empty map
gapTable = new int8_t[gapSize]; gapTable = new int8_t[gapSize];

View File

@ -900,8 +900,8 @@ void Segment::refreshLightCapabilities() {
segStopIdx = stop; segStopIdx = stop;
} }
for (unsigned b = 0; b < busses.getNumBusses(); b++) { for (unsigned b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = busses.getBus(b); Bus *bus = BusManager::getBus(b);
if (bus == nullptr || bus->getLength()==0) break; if (bus == nullptr || bus->getLength()==0) break;
if (!bus->isOk()) continue; if (!bus->isOk()) continue;
if (bus->getStart() >= segStopIdx) continue; if (bus->getStart() >= segStopIdx) continue;
@ -1086,7 +1086,7 @@ void WS2812FX::finalizeInit(void) {
_hasWhiteChannel = _isOffRefreshRequired = false; _hasWhiteChannel = _isOffRefreshRequired = false;
//if busses failed to load, add default (fresh install, FS issue, ...) //if busses failed to load, add default (fresh install, FS issue, ...)
if (busses.getNumBusses() == 0) { if (BusManager::getNumBusses() == 0) {
DEBUG_PRINTLN(F("No busses, init default")); DEBUG_PRINTLN(F("No busses, init default"));
const uint8_t defDataPins[] = {DATA_PINS}; const uint8_t defDataPins[] = {DATA_PINS};
const uint16_t defCounts[] = {PIXEL_COUNTS}; const uint16_t defCounts[] = {PIXEL_COUNTS};
@ -1099,13 +1099,13 @@ void WS2812FX::finalizeInit(void) {
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1]; uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
prevLen += count; prevLen += count;
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY); BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY);
if (busses.add(defCfg) == -1) break; if (BusManager::add(defCfg) == -1) break;
} }
} }
_length = 0; _length = 0;
for (int i=0; i<busses.getNumBusses(); i++) { for (int i=0; i<BusManager::getNumBusses(); i++) {
Bus *bus = busses.getBus(i); Bus *bus = BusManager::getBus(i);
if (bus == nullptr) continue; if (bus == nullptr) continue;
if (bus->getStart() + bus->getLength() > MAX_LEDS) break; if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
//RGBW mode is enabled if at least one of the strips is RGBW //RGBW mode is enabled if at least one of the strips is RGBW
@ -1164,7 +1164,7 @@ void WS2812FX::service() {
_colors_t[1] = gamma32(seg.currentColor(1)); _colors_t[1] = gamma32(seg.currentColor(1));
_colors_t[2] = gamma32(seg.currentColor(2)); _colors_t[2] = gamma32(seg.currentColor(2));
seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(true), correctWB); if (!cctFromRgb || correctWB) BusManager::setSegmentCCT(seg.currentBri(true), correctWB);
// Effect blending // Effect blending
// When two effects are being blended, each may have different segment data, this // When two effects are being blended, each may have different segment data, this
// data needs to be saved first and then restored before running previous mode. // data needs to be saved first and then restored before running previous mode.
@ -1195,7 +1195,7 @@ void WS2812FX::service() {
_segment_index++; _segment_index++;
} }
_virtualSegmentLength = 0; _virtualSegmentLength = 0;
busses.setSegmentCCT(-1); BusManager::setSegmentCCT(-1);
_isServicing = false; _isServicing = false;
_triggered = false; _triggered = false;
@ -1214,13 +1214,13 @@ void WS2812FX::service() {
void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) { void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) {
if (i < customMappingSize) i = customMappingTable[i]; if (i < customMappingSize) i = customMappingTable[i];
if (i >= _length) return; if (i >= _length) return;
busses.setPixelColor(i, col); BusManager::setPixelColor(i, col);
} }
uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) { uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) {
if (i < customMappingSize) i = customMappingTable[i]; if (i < customMappingSize) i = customMappingTable[i];
if (i >= _length) return 0; if (i >= _length) return 0;
return busses.getPixelColor(i); return BusManager::getPixelColor(i);
} }
void WS2812FX::show(void) { void WS2812FX::show(void) {
@ -1231,7 +1231,7 @@ void WS2812FX::show(void) {
// some buses send asynchronously and this method will return before // some buses send asynchronously and this method will return before
// all of the data has been sent. // all of the data has been sent.
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
busses.show(); BusManager::show();
unsigned long showNow = millis(); unsigned long showNow = millis();
size_t diff = showNow - _lastShow; size_t diff = showNow - _lastShow;
@ -1246,7 +1246,7 @@ void WS2812FX::show(void) {
* On some hardware (ESP32), strip updates are done asynchronously. * On some hardware (ESP32), strip updates are done asynchronously.
*/ */
bool WS2812FX::isUpdating() { bool WS2812FX::isUpdating() {
return !busses.canAllShow(); return !BusManager::canAllShow();
} }
/** /**
@ -1305,7 +1305,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
} }
// setting brightness with NeoPixelBusLg has no effect on already painted pixels, // setting brightness with NeoPixelBusLg has no effect on already painted pixels,
// so we need to force an update to existing buffer // so we need to force an update to existing buffer
busses.setBrightness(b); BusManager::setBrightness(b);
if (!direct) { if (!direct) {
unsigned long t = millis(); unsigned long t = millis();
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon
@ -1361,8 +1361,8 @@ uint16_t WS2812FX::getLengthTotal(void) {
uint16_t WS2812FX::getLengthPhysical(void) { uint16_t WS2812FX::getLengthPhysical(void) {
uint16_t len = 0; uint16_t len = 0;
for (size_t b = 0; b < busses.getNumBusses(); b++) { for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = busses.getBus(b); Bus *bus = BusManager::getBus(b);
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
len += bus->getLength(); len += bus->getLength();
} }
@ -1373,8 +1373,8 @@ uint16_t WS2812FX::getLengthPhysical(void) {
//returns if there is an RGBW bus (supports RGB and White, not only white) //returns if there is an RGBW bus (supports RGB and White, not only white)
//not influenced by auto-white mode, also true if white slider does not affect output white channel //not influenced by auto-white mode, also true if white slider does not affect output white channel
bool WS2812FX::hasRGBWBus(void) { bool WS2812FX::hasRGBWBus(void) {
for (size_t b = 0; b < busses.getNumBusses(); b++) { for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = busses.getBus(b); Bus *bus = BusManager::getBus(b);
if (bus == nullptr || bus->getLength()==0) break; if (bus == nullptr || bus->getLength()==0) break;
if (bus->hasRGB() && bus->hasWhite()) return true; if (bus->hasRGB() && bus->hasWhite()) return true;
} }
@ -1383,8 +1383,8 @@ bool WS2812FX::hasRGBWBus(void) {
bool WS2812FX::hasCCTBus(void) { bool WS2812FX::hasCCTBus(void) {
if (cctFromRgb && !correctWB) return false; if (cctFromRgb && !correctWB) return false;
for (size_t b = 0; b < busses.getNumBusses(); b++) { for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = busses.getBus(b); Bus *bus = BusManager::getBus(b);
if (bus == nullptr || bus->getLength()==0) break; if (bus == nullptr || bus->getLength()==0) break;
switch (bus->getType()) { switch (bus->getType()) {
case TYPE_ANALOG_5CH: case TYPE_ANALOG_5CH:
@ -1472,8 +1472,8 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
} }
#endif #endif
for (size_t i = s; i < busses.getNumBusses(); i++) { for (size_t i = s; i < BusManager::getNumBusses(); i++) {
Bus* b = busses.getBus(i); Bus* b = BusManager::getBus(i);
segStarts[s] = b->getStart(); segStarts[s] = b->getStart();
segStops[s] = segStarts[s] + b->getLength(); segStops[s] = segStarts[s] + b->getLength();
@ -1562,8 +1562,8 @@ void WS2812FX::fixInvalidSegments() {
bool WS2812FX::checkSegmentAlignment() { bool WS2812FX::checkSegmentAlignment() {
bool aligned = false; bool aligned = false;
for (segment &seg : _segments) { for (segment &seg : _segments) {
for (unsigned b = 0; b<busses.getNumBusses(); b++) { for (unsigned b = 0; b<BusManager::getNumBusses(); b++) {
Bus *bus = busses.getBus(b); Bus *bus = BusManager::getBus(b);
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true; if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
} }
if (seg.start == 0 && seg.stop == _length) aligned = true; if (seg.start == 0 && seg.stop == _length) aligned = true;
@ -1670,7 +1670,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
if (!isFile || !requestJSONBufferLock(7)) return false; // this will trigger setUpMatrix() when called from wled.cpp if (!isFile || !requestJSONBufferLock(7)) return false; // this will trigger setUpMatrix() when called from wled.cpp
if (!readObjectFromFile(fileName, nullptr, &doc)) { if (!readObjectFromFile(fileName, nullptr, pDoc)) {
DEBUG_PRINT(F("ERROR Invalid ledmap in ")); DEBUG_PRINTLN(fileName); DEBUG_PRINT(F("ERROR Invalid ledmap in ")); DEBUG_PRINTLN(fileName);
releaseJSONBufferLock(); releaseJSONBufferLock();
return false; // if file does not load properly then exit return false; // if file does not load properly then exit
@ -1680,7 +1680,8 @@ bool WS2812FX::deserializeMap(uint8_t n) {
if (customMappingTable == nullptr) customMappingTable = new uint16_t[getLengthTotal()]; if (customMappingTable == nullptr) customMappingTable = new uint16_t[getLengthTotal()];
JsonArray map = doc[F("map")]; JsonObject root = pDoc->as<JsonObject>();
JsonArray map = root[F("map")];
if (!map.isNull() && map.size()) { // not an empty map if (!map.isNull() && map.size()) { // not an empty map
customMappingSize = min((unsigned)map.size(), (unsigned)getLengthTotal()); customMappingSize = min((unsigned)map.size(), (unsigned)getLengthTotal());
for (unsigned i=0; i<customMappingSize; i++) customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]); for (unsigned i=0; i<customMappingSize; i++) customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);

View File

@ -125,7 +125,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz); _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz);
_valid = (_busPtr != nullptr); _valid = (_busPtr != nullptr);
DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], _pins[1], _iType); DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n", _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], _pins[1], _iType, _milliAmpsPerLed, _milliAmpsMax);
} }
//fine tune power estimation constants for your setup //fine tune power estimation constants for your setup
@ -150,7 +150,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
bool useWackyWS2815PowerModel = false; bool useWackyWS2815PowerModel = false;
byte actualMilliampsPerLed = _milliAmpsPerLed; byte actualMilliampsPerLed = _milliAmpsPerLed;
if (_milliAmpsMax < MA_FOR_ESP || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation if (_milliAmpsMax < MA_FOR_ESP/BusManager::getNumBusses() || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
return _bri; return _bri;
} }
@ -159,7 +159,12 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
actualMilliampsPerLed = 12; // from testing an actual strip actualMilliampsPerLed = 12; // from testing an actual strip
} }
size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP); //100mA for ESP power size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power
if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget
powerBudget -= getLength();
} else {
powerBudget = 0;
}
uint32_t busPowerSum = 0; uint32_t busPowerSum = 0;
for (unsigned i = 0; i < getLength(); i++) { //sum up the usage of each LED for (unsigned i = 0; i < getLength(); i++) { //sum up the usage of each LED
@ -178,29 +183,26 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
busPowerSum >>= 2; //same as /= 4 busPowerSum >>= 2; //same as /= 4
} }
if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget
powerBudget -= getLength();
} else {
powerBudget = 0;
}
// powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps // powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps
busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765; busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765;
_milliAmpsTotal = busPowerSum * _bri / 255;
uint8_t newBri = _bri; uint8_t newBri = _bri;
if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit
float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri); float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri);
uint16_t scaleI = scale * 255; if (scale >= 1.0f) return _bri;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; _milliAmpsTotal = ceilf((float)_milliAmpsTotal * scale);
uint8_t scaleB = min((int)(scale * 255), 255);
newBri = unsigned(_bri * scaleB) / 256 + 1; newBri = unsigned(_bri * scaleB) / 256 + 1;
} }
return newBri; return newBri;
} }
void BusDigital::show() { void BusDigital::show() {
_milliAmpsTotal = 0;
if (!_valid) return; if (!_valid) return;
uint8_t newBri = estimateCurrentAndLimitBri(); uint8_t newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal
if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits
if (_data) { // use _buffering this causes ~20% FPS drop if (_data) { // use _buffering this causes ~20% FPS drop
@ -646,9 +648,12 @@ void BusManager::removeAll() {
} }
void BusManager::show() { void BusManager::show() {
_milliAmpsUsed = 0;
for (unsigned i = 0; i < numBusses; i++) { for (unsigned i = 0; i < numBusses; i++) {
busses[i]->show(); busses[i]->show();
_milliAmpsUsed += busses[i]->getUsedCurrent();
} }
if (_milliAmpsUsed) _milliAmpsUsed += MA_FOR_ESP;
} }
void BusManager::setStatusPixel(uint32_t c) { void BusManager::setStatusPixel(uint32_t c) {
@ -714,3 +719,11 @@ uint16_t BusManager::getTotalLength() {
int16_t Bus::_cct = -1; int16_t Bus::_cct = -1;
uint8_t Bus::_cctBlend = 0; uint8_t Bus::_cctBlend = 0;
uint8_t Bus::_gAWM = 255; uint8_t Bus::_gAWM = 255;
uint16_t BusDigital::_milliAmpsTotal = 0;
uint8_t BusManager::numBusses = 0;
Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
ColorOrderMap BusManager::colorOrderMap = {};
uint16_t BusManager::_milliAmpsUsed = 0;
uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT;

View File

@ -137,6 +137,7 @@ class Bus {
virtual uint8_t skippedLeds() { return 0; } virtual uint8_t skippedLeds() { return 0; }
virtual uint16_t getFrequency() { return 0U; } virtual uint16_t getFrequency() { return 0U; }
virtual uint16_t getLEDCurrent() { return 0; } virtual uint16_t getLEDCurrent() { return 0; }
virtual uint16_t getUsedCurrent() { return 0; }
virtual uint16_t getMaxCurrent() { return 0; } virtual uint16_t getMaxCurrent() { return 0; }
inline void setReversed(bool reversed) { _reversed = reversed; } inline void setReversed(bool reversed) { _reversed = reversed; }
inline uint16_t getStart() { return _start; } inline uint16_t getStart() { return _start; }
@ -219,6 +220,7 @@ class BusDigital : public Bus {
uint16_t getFrequency() { return _frequencykHz; } uint16_t getFrequency() { return _frequencykHz; }
uint8_t estimateCurrentAndLimitBri(); uint8_t estimateCurrentAndLimitBri();
uint16_t getLEDCurrent() { return _milliAmpsPerLed; } uint16_t getLEDCurrent() { return _milliAmpsPerLed; }
uint16_t getUsedCurrent() { return _milliAmpsTotal; }
uint16_t getMaxCurrent() { return _milliAmpsMax; } uint16_t getMaxCurrent() { return _milliAmpsMax; }
void reinit(); void reinit();
void cleanup(); void cleanup();
@ -233,7 +235,8 @@ class BusDigital : public Bus {
uint16_t _milliAmpsMax; uint16_t _milliAmpsMax;
void * _busPtr; void * _busPtr;
const ColorOrderMap &_colorOrderMap; const ColorOrderMap &_colorOrderMap;
//bool _buffering; // temporary until we figure out why comparison "_data" causes severe FPS drop
static uint16_t _milliAmpsTotal; // is overwitten/recalculated on each show()
inline uint32_t restoreColorLossy(uint32_t c, uint8_t restoreBri) { inline uint32_t restoreColorLossy(uint32_t c, uint8_t restoreBri) {
if (restoreBri < 255) { if (restoreBri < 255) {
@ -314,39 +317,44 @@ class BusNetwork : public Bus {
class BusManager { class BusManager {
public: public:
BusManager() : numBusses(0) {}; 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);
static uint16_t currentMilliamps(void) { return _milliAmpsUsed; }
static uint16_t ablMilliampsMax(void) { return _milliAmpsMax; }
int add(BusConfig &bc); static int add(BusConfig &bc);
//do not call this method from system context (network callback) //do not call this method from system context (network callback)
void removeAll(); static void removeAll();
void show(); static void show();
bool canAllShow(); static bool canAllShow();
void setStatusPixel(uint32_t c); static void setStatusPixel(uint32_t c);
void setPixelColor(uint16_t pix, uint32_t c); static void setPixelColor(uint16_t pix, uint32_t c);
void setBrightness(uint8_t b); static void setBrightness(uint8_t b);
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
uint32_t getPixelColor(uint16_t pix); static void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
static uint32_t getPixelColor(uint16_t pix);
Bus* getBus(uint8_t busNr); static Bus* getBus(uint8_t busNr);
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
uint16_t getTotalLength(); static uint16_t getTotalLength();
inline uint8_t getNumBusses() const { return numBusses; } static uint8_t getNumBusses() { return numBusses; }
inline void updateColorOrderMap(const ColorOrderMap &com) { memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); } static void updateColorOrderMap(const ColorOrderMap &com) { memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); }
inline const ColorOrderMap& getColorOrderMap() const { return colorOrderMap; } static const ColorOrderMap& getColorOrderMap() { return colorOrderMap; }
private: private:
uint8_t numBusses; static uint8_t numBusses;
Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; static Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
ColorOrderMap colorOrderMap; static ColorOrderMap colorOrderMap;
static uint16_t _milliAmpsUsed;
static uint16_t _milliAmpsMax;
inline uint8_t getNumVirtualBusses() { static 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;

View File

@ -347,10 +347,10 @@ void handleButton()
void esp32RMTInvertIdle() void esp32RMTInvertIdle()
{ {
bool idle_out; bool idle_out;
for (uint8_t u = 0; u < busses.getNumBusses(); u++) for (uint8_t u = 0; u < BusManager::getNumBusses(); u++)
{ {
if (u > 7) return; // only 8 RMT channels, TODO: ESP32 variants have less RMT channels if (u > 7) return; // only 8 RMT channels, TODO: ESP32 variants have less RMT channels
Bus *bus = busses.getBus(u); Bus *bus = BusManager::getBus(u);
if (!bus || bus->getLength()==0 || !IS_DIGITAL(bus->getType()) || IS_2PIN(bus->getType())) continue; if (!bus || bus->getLength()==0 || !IS_DIGITAL(bus->getType()) || IS_2PIN(bus->getType())) continue;
//assumes that bus number to rmt channel mapping stays 1:1 //assumes that bus number to rmt channel mapping stays 1:1
rmt_channel_t ch = static_cast<rmt_channel_t>(u); rmt_channel_t ch = static_cast<rmt_channel_t>(u);

View File

@ -87,8 +87,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject hw_led = hw["led"]; JsonObject hw_led = hw["led"];
uint16_t total = hw_led[F("total")] | strip.getLengthTotal(); uint16_t total = hw_led[F("total")] | strip.getLengthTotal();
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); uint16_t ablMilliampsMax = hw_led[F("maxpwr")] | BusManager::ablMilliampsMax();
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); // no longer used BusManager::setMilliampsMax(ablMilliampsMax);
Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED); Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED);
CJSON(correctWB, hw_led["cct"]); CJSON(correctWB, hw_led["cct"]);
CJSON(cctFromRgb, hw_led[F("cr")]); CJSON(cctFromRgb, hw_led[F("cr")]);
@ -138,7 +138,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (fromFS || !ins.isNull()) { if (fromFS || !ins.isNull()) {
uint8_t s = 0; // bus iterator uint8_t s = 0; // bus iterator
if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
uint32_t mem = 0, globalBufMem = 0; uint32_t mem = 0, globalBufMem = 0;
uint16_t maxlen = 0; uint16_t maxlen = 0;
bool busesChanged = false; bool busesChanged = false;
@ -164,8 +164,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
bool refresh = elm["ref"] | false; bool refresh = elm["ref"] | false;
uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully) uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully)
uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY; uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY;
uint8_t maPerLed = elm[F("ledma")] | strip.milliampsPerLed; // replace with 55 when removing strip.milliampsPerLed uint8_t maPerLed = elm[F("ledma")] | 55;
uint16_t maMax = elm[F("maxpwr")] | (strip.ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists uint16_t maMax = elm[F("maxpwr")] | (ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists
// To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current) // To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current)
if ((ledType > TYPE_TM1814 && ledType < TYPE_WS2801) || ledType >= TYPE_NET_DDP_RGB) { // analog and virtual if ((ledType > TYPE_TM1814 && ledType < TYPE_WS2801) || ledType >= TYPE_NET_DDP_RGB) { // analog and virtual
maPerLed = 0; maPerLed = 0;
@ -179,7 +179,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
maxlen = start + length; maxlen = start + length;
globalBufMem = maxlen * 4; globalBufMem = maxlen * 4;
} }
if (mem + globalBufMem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break; // finalization will be done in WLED::beginStrip() if (mem + globalBufMem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
} else { } else {
if (busConfigs[s] != nullptr) delete busConfigs[s]; if (busConfigs[s] != nullptr) delete busConfigs[s];
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
@ -190,7 +190,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
doInitBusses = busesChanged; doInitBusses = busesChanged;
// finalization done in beginStrip() // finalization done in beginStrip()
} }
if (hw_led["rev"]) busses.getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
// read color order map configuration // read color order map configuration
JsonArray hw_com = hw[F("com")]; JsonArray hw_com = hw[F("com")];
@ -205,7 +205,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
com.add(start, len, colorOrder); com.add(start, len, colorOrder);
s++; s++;
} }
busses.updateColorOrderMap(com); BusManager::updateColorOrderMap(com);
} }
// read multiple button configuration // read multiple button configuration
@ -609,7 +609,7 @@ void deserializeConfigFromFS() {
DEBUG_PRINTLN(F("Reading settings from /cfg.json...")); DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
success = readObjectFromFile("/cfg.json", nullptr, &doc); success = readObjectFromFile("/cfg.json", nullptr, pDoc);
if (!success) { // if file does not exist, optionally try reading from EEPROM and then save defaults to FS if (!success) { // if file does not exist, optionally try reading from EEPROM and then save defaults to FS
releaseJSONBufferLock(); releaseJSONBufferLock();
#ifdef WLED_ADD_EEPROM_SUPPORT #ifdef WLED_ADD_EEPROM_SUPPORT
@ -630,7 +630,8 @@ void deserializeConfigFromFS() {
// NOTE: This routine deserializes *and* applies the configuration // NOTE: This routine deserializes *and* applies the configuration
// Therefore, must also initialize ethernet from this function // Therefore, must also initialize ethernet from this function
bool needsSave = deserializeConfig(doc.as<JsonObject>(), true); JsonObject root = pDoc->as<JsonObject>();
bool needsSave = deserializeConfig(root, true);
releaseJSONBufferLock(); releaseJSONBufferLock();
if (needsSave) serializeConfig(); // usermods required new parameters if (needsSave) serializeConfig(); // usermods required new parameters
@ -643,19 +644,21 @@ void serializeConfig() {
if (!requestJSONBufferLock(2)) return; if (!requestJSONBufferLock(2)) return;
JsonArray rev = doc.createNestedArray("rev"); JsonObject root = pDoc->to<JsonObject>();
JsonArray rev = root.createNestedArray("rev");
rev.add(1); //major settings revision rev.add(1); //major settings revision
rev.add(0); //minor settings revision rev.add(0); //minor settings revision
doc[F("vid")] = VERSION; root[F("vid")] = VERSION;
JsonObject id = doc.createNestedObject("id"); JsonObject id = root.createNestedObject("id");
id[F("mdns")] = cmDNS; id[F("mdns")] = cmDNS;
id[F("name")] = serverDescription; id[F("name")] = serverDescription;
id[F("inv")] = alexaInvocationName; id[F("inv")] = alexaInvocationName;
id[F("sui")] = simplifiedUI; id[F("sui")] = simplifiedUI;
JsonObject nw = doc.createNestedObject("nw"); JsonObject nw = root.createNestedObject("nw");
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW
nw[F("espnow")] = enableESPNow; nw[F("espnow")] = enableESPNow;
nw[F("linked_remote")] = linked_remote; nw[F("linked_remote")] = linked_remote;
@ -677,7 +680,7 @@ void serializeConfig() {
nw_ins_0_sn.add(staticSubnet[i]); nw_ins_0_sn.add(staticSubnet[i]);
} }
JsonObject ap = doc.createNestedObject("ap"); JsonObject ap = root.createNestedObject("ap");
ap[F("ssid")] = apSSID; ap[F("ssid")] = apSSID;
ap[F("pskl")] = strlen(apPass); ap[F("pskl")] = strlen(apPass);
ap[F("chan")] = apChannel; ap[F("chan")] = apChannel;
@ -690,12 +693,12 @@ void serializeConfig() {
ap_ip.add(2); ap_ip.add(2);
ap_ip.add(1); ap_ip.add(1);
JsonObject wifi = doc.createNestedObject("wifi"); JsonObject wifi = root.createNestedObject("wifi");
wifi[F("sleep")] = !noWifiSleep; wifi[F("sleep")] = !noWifiSleep;
wifi[F("phy")] = (int)force802_3g; wifi[F("phy")] = (int)force802_3g;
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
JsonObject ethernet = doc.createNestedObject("eth"); JsonObject ethernet = root.createNestedObject("eth");
ethernet["type"] = ethernetType; ethernet["type"] = ethernetType;
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
JsonArray pins = ethernet.createNestedArray("pin"); JsonArray pins = ethernet.createNestedArray("pin");
@ -718,12 +721,12 @@ void serializeConfig() {
} }
#endif #endif
JsonObject hw = doc.createNestedObject("hw"); JsonObject hw = root.createNestedObject("hw");
JsonObject hw_led = hw.createNestedObject("led"); JsonObject hw_led = hw.createNestedObject("led");
hw_led[F("total")] = strip.getLengthTotal(); //provided for compatibility on downgrade and per-output ABL hw_led[F("total")] = strip.getLengthTotal(); //provided for compatibility on downgrade and per-output ABL
hw_led[F("maxpwr")] = strip.ablMilliampsMax; hw_led[F("maxpwr")] = BusManager::ablMilliampsMax();
hw_led[F("ledma")] = strip.milliampsPerLed; // no longer used hw_led[F("ledma")] = 0; // no longer used
hw_led["cct"] = correctWB; hw_led["cct"] = correctWB;
hw_led[F("cr")] = cctFromRgb; hw_led[F("cr")] = cctFromRgb;
hw_led[F("cb")] = strip.cctBlending; hw_led[F("cb")] = strip.cctBlending;
@ -753,8 +756,8 @@ void serializeConfig() {
JsonArray hw_led_ins = hw_led.createNestedArray("ins"); JsonArray hw_led_ins = hw_led.createNestedArray("ins");
for (uint8_t s = 0; s < busses.getNumBusses(); s++) { for (uint8_t s = 0; s < BusManager::getNumBusses(); s++) {
Bus *bus = busses.getBus(s); Bus *bus = BusManager::getBus(s);
if (!bus || bus->getLength()==0) break; if (!bus || bus->getLength()==0) break;
JsonObject ins = hw_led_ins.createNestedObject(); JsonObject ins = hw_led_ins.createNestedObject();
ins["start"] = bus->getStart(); ins["start"] = bus->getStart();
@ -775,7 +778,7 @@ void serializeConfig() {
} }
JsonArray hw_com = hw.createNestedArray(F("com")); JsonArray hw_com = hw.createNestedArray(F("com"));
const ColorOrderMap& com = busses.getColorOrderMap(); const ColorOrderMap& com = BusManager::getColorOrderMap();
for (uint8_t s = 0; s < com.count(); s++) { for (uint8_t s = 0; s < com.count(); s++) {
const ColorOrderMapEntry *entry = com.get(s); const ColorOrderMapEntry *entry = com.get(s);
if (!entry) break; if (!entry) break;
@ -830,7 +833,7 @@ void serializeConfig() {
//JsonObject hw_status = hw.createNestedObject("status"); //JsonObject hw_status = hw.createNestedObject("status");
//hw_status["pin"] = -1; //hw_status["pin"] = -1;
JsonObject light = doc.createNestedObject(F("light")); JsonObject light = root.createNestedObject(F("light"));
light[F("scale-bri")] = briMultiplier; light[F("scale-bri")] = briMultiplier;
light[F("pal-mode")] = strip.paletteBlend; light[F("pal-mode")] = strip.paletteBlend;
light[F("aseg")] = autoSegments; light[F("aseg")] = autoSegments;
@ -853,12 +856,12 @@ void serializeConfig() {
light_nl[F("tbri")] = nightlightTargetBri; light_nl[F("tbri")] = nightlightTargetBri;
light_nl["macro"] = macroNl; light_nl["macro"] = macroNl;
JsonObject def = doc.createNestedObject("def"); JsonObject def = root.createNestedObject("def");
def["ps"] = bootPreset; def["ps"] = bootPreset;
def["on"] = turnOnAtBoot; def["on"] = turnOnAtBoot;
def["bri"] = briS; def["bri"] = briS;
JsonObject interfaces = doc.createNestedObject("if"); JsonObject interfaces = root.createNestedObject("if");
JsonObject if_sync = interfaces.createNestedObject("sync"); JsonObject if_sync = interfaces.createNestedObject("sync");
if_sync[F("port0")] = udpPort; if_sync[F("port0")] = udpPort;
@ -961,7 +964,7 @@ void serializeConfig() {
if_ntp[F("ln")] = longitude; if_ntp[F("ln")] = longitude;
if_ntp[F("lt")] = latitude; if_ntp[F("lt")] = latitude;
JsonObject ol = doc.createNestedObject("ol"); JsonObject ol = root.createNestedObject("ol");
ol[F("clock")] = overlayCurrent; ol[F("clock")] = overlayCurrent;
ol[F("cntdwn")] = countdownMode; ol[F("cntdwn")] = countdownMode;
@ -971,7 +974,7 @@ void serializeConfig() {
ol[F("o5m")] = analogClock5MinuteMarks; ol[F("o5m")] = analogClock5MinuteMarks;
ol[F("osec")] = analogClockSecondsTrail; ol[F("osec")] = analogClockSecondsTrail;
JsonObject timers = doc.createNestedObject(F("timers")); JsonObject timers = root.createNestedObject(F("timers"));
JsonObject cntdwn = timers.createNestedObject(F("cntdwn")); JsonObject cntdwn = timers.createNestedObject(F("cntdwn"));
JsonArray goal = cntdwn.createNestedArray(F("goal")); JsonArray goal = cntdwn.createNestedArray(F("goal"));
@ -999,14 +1002,14 @@ void serializeConfig() {
} }
} }
JsonObject ota = doc.createNestedObject("ota"); JsonObject ota = root.createNestedObject("ota");
ota[F("lock")] = otaLock; ota[F("lock")] = otaLock;
ota[F("lock-wifi")] = wifiLock; ota[F("lock-wifi")] = wifiLock;
ota[F("pskl")] = strlen(otaPass); ota[F("pskl")] = strlen(otaPass);
ota[F("aota")] = aOtaEnabled; ota[F("aota")] = aOtaEnabled;
#ifdef WLED_ENABLE_DMX #ifdef WLED_ENABLE_DMX
JsonObject dmx = doc.createNestedObject("dmx"); JsonObject dmx = root.createNestedObject("dmx");
dmx[F("chan")] = DMXChannels; dmx[F("chan")] = DMXChannels;
dmx[F("gap")] = DMXGap; dmx[F("gap")] = DMXGap;
dmx["start"] = DMXStart; dmx["start"] = DMXStart;
@ -1020,11 +1023,11 @@ void serializeConfig() {
dmx[F("e131proxy")] = e131ProxyUniverse; dmx[F("e131proxy")] = e131ProxyUniverse;
#endif #endif
JsonObject usermods_settings = doc.createNestedObject("um"); JsonObject usermods_settings = root.createNestedObject("um");
usermods.addToConfig(usermods_settings); usermods.addToConfig(usermods_settings);
File f = WLED_FS.open("/cfg.json", "w"); File f = WLED_FS.open("/cfg.json", "w");
if (f) serializeJson(doc, f); if (f) serializeJson(root, f);
f.close(); f.close();
releaseJSONBufferLock(); releaseJSONBufferLock();
@ -1037,19 +1040,21 @@ bool deserializeConfigSec() {
if (!requestJSONBufferLock(3)) return false; if (!requestJSONBufferLock(3)) return false;
bool success = readObjectFromFile("/wsec.json", nullptr, &doc); bool success = readObjectFromFile("/wsec.json", nullptr, pDoc);
if (!success) { if (!success) {
releaseJSONBufferLock(); releaseJSONBufferLock();
return false; return false;
} }
JsonObject nw_ins_0 = doc["nw"]["ins"][0]; JsonObject root = pDoc->as<JsonObject>();
JsonObject nw_ins_0 = root["nw"]["ins"][0];
getStringFromJson(clientPass, nw_ins_0["psk"], 65); getStringFromJson(clientPass, nw_ins_0["psk"], 65);
JsonObject ap = doc["ap"]; JsonObject ap = root["ap"];
getStringFromJson(apPass, ap["psk"] , 65); getStringFromJson(apPass, ap["psk"] , 65);
[[maybe_unused]] JsonObject interfaces = doc["if"]; [[maybe_unused]] JsonObject interfaces = root["if"];
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"]; JsonObject if_mqtt = interfaces["mqtt"];
@ -1060,10 +1065,10 @@ bool deserializeConfigSec() {
getStringFromJson(hueApiKey, interfaces["hue"][F("key")], 47); getStringFromJson(hueApiKey, interfaces["hue"][F("key")], 47);
#endif #endif
getStringFromJson(settingsPIN, doc["pin"], 5); getStringFromJson(settingsPIN, root["pin"], 5);
correctPIN = !strlen(settingsPIN); correctPIN = !strlen(settingsPIN);
JsonObject ota = doc["ota"]; JsonObject ota = root["ota"];
getStringFromJson(otaPass, ota[F("pwd")], 33); getStringFromJson(otaPass, ota[F("pwd")], 33);
CJSON(otaLock, ota[F("lock")]); CJSON(otaLock, ota[F("lock")]);
CJSON(wifiLock, ota[F("lock-wifi")]); CJSON(wifiLock, ota[F("lock-wifi")]);
@ -1078,17 +1083,19 @@ void serializeConfigSec() {
if (!requestJSONBufferLock(4)) return; if (!requestJSONBufferLock(4)) return;
JsonObject nw = doc.createNestedObject("nw"); JsonObject root = pDoc->to<JsonObject>();
JsonObject nw = root.createNestedObject("nw");
JsonArray nw_ins = nw.createNestedArray("ins"); JsonArray nw_ins = nw.createNestedArray("ins");
JsonObject nw_ins_0 = nw_ins.createNestedObject(); JsonObject nw_ins_0 = nw_ins.createNestedObject();
nw_ins_0["psk"] = clientPass; nw_ins_0["psk"] = clientPass;
JsonObject ap = doc.createNestedObject("ap"); JsonObject ap = root.createNestedObject("ap");
ap["psk"] = apPass; ap["psk"] = apPass;
[[maybe_unused]] JsonObject interfaces = doc.createNestedObject("if"); [[maybe_unused]] JsonObject interfaces = root.createNestedObject("if");
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt["psk"] = mqttPass; if_mqtt["psk"] = mqttPass;
@ -1098,16 +1105,16 @@ void serializeConfigSec() {
if_hue[F("key")] = hueApiKey; if_hue[F("key")] = hueApiKey;
#endif #endif
doc["pin"] = settingsPIN; root["pin"] = settingsPIN;
JsonObject ota = doc.createNestedObject("ota"); JsonObject ota = root.createNestedObject("ota");
ota[F("pwd")] = otaPass; ota[F("pwd")] = otaPass;
ota[F("lock")] = otaLock; ota[F("lock")] = otaLock;
ota[F("lock-wifi")] = wifiLock; ota[F("lock-wifi")] = wifiLock;
ota[F("aota")] = aOtaEnabled; ota[F("aota")] = aOtaEnabled;
File f = WLED_FS.open("/wsec.json", "w"); File f = WLED_FS.open("/wsec.json", "w");
if (f) serializeJson(doc, f); if (f) serializeJson(root, f);
f.close(); f.close();
releaseJSONBufferLock(); releaseJSONBufferLock();
} }

View File

@ -450,7 +450,11 @@
#ifdef ESP8266 #ifdef ESP8266
#define JSON_BUFFER_SIZE 10240 #define JSON_BUFFER_SIZE 10240
#else #else
#define JSON_BUFFER_SIZE 24576 #if defined(ARDUINO_ARCH_ESP32S2)
#define JSON_BUFFER_SIZE 24576
#else
#define JSON_BUFFER_SIZE 32767
#endif
#endif #endif
//#define MIN_HEAP_SIZE (8k for AsyncWebServer) //#define MIN_HEAP_SIZE (8k for AsyncWebServer)

View File

@ -1,6 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0"> <meta http-equiv="Expires" content="0">
@ -45,6 +46,7 @@
width: 7px; width: 7px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
touch-action: none;
} }
.color-picker-marker { .color-picker-marker {
height: 7px; height: 7px;
@ -94,9 +96,14 @@
line-height: 1; line-height: 1;
} }
.wrap { .wrap {
width: 800px; width: 100%;
margin: 0 auto; margin: 0 auto;
} }
@media (min-width: 800px) {
.wrap {
width: 800px;
}
}
.palette { .palette {
height: 20px; height: 20px;
} }
@ -136,6 +143,9 @@
.sendSpan, .editSpan{ .sendSpan, .editSpan{
cursor: pointer; cursor: pointer;
} }
h1 {
font-size: 1.6rem;
}
</style> </style>
</head> </head>
<body> <body>
@ -349,24 +359,31 @@
var gradientLength = maxX - minX + 1; var gradientLength = maxX - minX + 1;
elmnt.onmousedown = dragMouseDown; elmnt.onmousedown = dragMouseDown;
elmnt.ontouchstart = dragMouseDown;
function dragMouseDown(e) { function dragMouseDown(e) {
removeTrashcan(event) removeTrashcan(event)
e = e || window.event; e = e || window.event;
e.preventDefault(); var isTouch = e.type.startsWith('touch');
if (!isTouch) e.preventDefault();
// get the mouse cursor position at startup: // get the mouse cursor position at startup:
mousePos = e.clientX; mousePos = isTouch ? e.touches[0].clientX : e.clientX;
d.onmouseup = closeDragElement; d.onmouseup = closeDragElement;
d.ontouchcancel = closeDragElement;
d.ontouchend = closeDragElement;
// call a function whenever the cursor moves: // call a function whenever the cursor moves:
d.onmousemove = elementDrag; d.onmousemove = elementDrag;
d.ontouchmove = elementDrag;
} }
function elementDrag(e) { function elementDrag(e) {
e = e || window.event; e = e || window.event;
e.preventDefault(); var isTouch = e.type.startsWith('touch');
if (!isTouch) e.preventDefault();
// calculate the new cursor position: // calculate the new cursor position:
posNew = mousePos - e.clientX; var clientX = isTouch ? e.touches[0].clientX : e.clientX;
mousePos = e.clientX; posNew = mousePos - clientX;
mousePos = clientX;
mousePosInGradient = mousePos - (minX + 1) mousePosInGradient = mousePos - (minX + 1)
truePos = Math.round((mousePosInGradient/gradientLength)*256); truePos = Math.round((mousePosInGradient/gradientLength)*256);
@ -393,7 +410,10 @@
function closeDragElement() { function closeDragElement() {
/* stop moving when mouse button is released:*/ /* stop moving when mouse button is released:*/
d.onmouseup = null; d.onmouseup = null;
d.ontouchcancel = null;
d.ontouchend = null;
d.onmousemove = null; d.onmousemove = null;
d.ontouchmove = null;
} }
} }

View File

@ -26,8 +26,8 @@
// success event // success event
scE.addEventListener("load", () => { scE.addEventListener("load", () => {
GetV(); GetV();
setABL();
checkSi(); checkSi();
setABL();
d.Sf.addEventListener("submit", trySubmit); d.Sf.addEventListener("submit", trySubmit);
if (d.um_p[0]==-1) d.um_p.shift(); if (d.um_p[0]==-1) d.um_p.shift();
pinDropdowns(); pinDropdowns();
@ -107,30 +107,36 @@
e.preventDefault(); e.preventDefault();
if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);} if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
if (!d.Sf.ABL.checked || d.Sf.PPL.checked) d.Sf.MA.value = 0; // submit 0 as ABL (PPL will handle it)
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914 if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
} }
function enABL() function enABL()
{ {
var en = d.Sf["ABL"].checked; var en = d.Sf.ABL.checked;
d.Sf["MA"].min = en ? 250 : 0;
gId('abl').style.display = (en) ? 'inline':'none'; gId('abl').style.display = (en) ? 'inline':'none';
gId('psu2').style.display = (en) ? 'inline':'none'; gId('psu2').style.display = (en) ? 'inline':'none';
if (!en) d.Sf["PPL"].checked = false; if (!en) d.Sf.PPL.checked = false;
enPPL(); enPPL();
UI(); UI();
} }
function enPPL() function enPPL()
{ {
const abl = d.Sf["ABL"].checked; const abl = d.Sf.ABL.checked;
const en = d.Sf["PPL"].checked; const ppl = d.Sf.PPL.checked;
d.Sf["MA"].readonly = en; let sumMA = 0;
gId("ppldis").style.display = en ? 'inline' : 'none'; d.Sf.MA.readonly = ppl;
d.Sf.MA.min = abl && !ppl ? 250 : 0;
gId("psuMA").style.display = ppl ? 'none' : 'inline';
gId("ppldis").style.display = ppl ? 'inline' : 'none';
// set PPL minimum value and clear actual PPL limit if ABL disabled
d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{ d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{
gId("PSU"+n).style.display = en ? "inline" : "none"; gId("PSU"+n).style.display = ppl ? "inline" : "none";
const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
i.min = en && !((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 250 : 0; i.min = ppl && !((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 250 : 0;
if (!abl) i.value = 0; if (!abl) i.value = 0;
else if (ppl) sumMA += parseInt(i.value,10);
}); });
if (ppl) d.Sf.MA.value = sumMA; // populate UI ABL value if PPL used
} }
function enLA(s,n) function enLA(s,n)
{ {
@ -141,10 +147,11 @@
} }
function setABL() function setABL()
{ {
d.Sf["ABL"].checked = false; console.log(d.Sf.MA.value);
d.Sf.ABL.checked = parseInt(d.Sf.MA.value) > 0;
// check if ABL is enabled (max mA entered per output) // check if ABL is enabled (max mA entered per output)
d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{ d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{
if (parseInt(i.value) > 0) d.Sf["ABL"].checked = true; if (parseInt(i.value) > 0) d.Sf.ABL.checked = true;
}); });
// select appropriate LED current // select appropriate LED current
d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((sel,n)=>{ d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((sel,n)=>{
@ -190,8 +197,8 @@
let isRGBW = false, gRGBW = false, memu = 0; let isRGBW = false, gRGBW = false, memu = 0;
let sumMA = 0, busMA = 0; let sumMA = 0, busMA = 0;
let sLC = 0, sPC = 0, sDI = 0, maxLC = 0; let sLC = 0, sPC = 0, sDI = 0, maxLC = 0;
const ablEN = d.Sf["ABL"].checked; const ablEN = d.Sf.ABL.checked;
const pplEN = d.Sf["PPL"].checked; const pplEN = d.Sf.PPL.checked;
// enable/disable LED fields // enable/disable LED fields
d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((s)=>{ d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((s)=>{
@ -244,7 +251,7 @@
gId("rev"+n).innerHTML = (t >= 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog gId("rev"+n).innerHTML = (t >= 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description
if (ablEN && pplEN && !((t >= 80 && t < 96) || (t >= 40 && t < 48))) { if (ablEN && pplEN && !((t >= 80 && t < 96) || (t >= 40 && t < 48))) {
sumMA += parseInt(d.Sf["MA"+n].value); sumMA += parseInt(d.Sf["MA"+n].value); // summarize PPL ABL limit (fields)
} }
}); });
// display global white channel overrides // display global white channel overrides
@ -269,11 +276,12 @@
if (s+c > sLC) sLC = s+c; //update total count if (s+c > sLC) sLC = s+c; //update total count
if (c > maxLC) maxLC = c; //max per output if (c > maxLC) maxLC = c; //max per output
if (t < 80) sPC += c; //virtual out busses do not count towards physical LEDs if (t < 80) sPC += c; //virtual out busses do not count towards physical LEDs
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) sDI += c; //if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) sDI += c;
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) { if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) {
sDI += c; // summarize digital LED count
let maPL = parseInt(d.Sf["LA"+n].value); let maPL = parseInt(d.Sf["LA"+n].value);
if (maPL == 255) maPL = 12; if (maPL == 255) maPL = 12;
busMA += maPL*c; busMA += maPL*c; // summarize maximum bus current (calculated)
} }
} // increase led count } // increase led count
return; return;
@ -316,14 +324,18 @@
else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff";
} }
}); });
// distribute ABL current if not using PPL, otherwise sumMA contains summarized ABL limit
d.Sf.querySelectorAll("#mLC input[name^=LC]").forEach((s,n)=>{ d.Sf.querySelectorAll("#mLC input[name^=LC]").forEach((s,n)=>{
let c = parseInt(s.value,10); //get LED count let c = parseInt(s.value,10); //get LED count
let t = parseInt(d.Sf["LT"+n].value); let t = parseInt(d.Sf["LT"+n].value); //get LED type
if (ablEN) { if (!ablEN || (t >= 80 && t < 96) || (t >= 40 && t < 48)) {
let v = Math.round(parseInt(d.Sf["MA"].value,10)*c/sDI); // virtual and analog LEDs have no limiter
if (!pplEN && !((t >= 80 && t < 96) || (t >= 40 && t < 48))) d.Sf["MA"+n].value = v; d.Sf["MA"+n].value = 0;
} else d.Sf["MA"+n].value = 0; return;
}
if (!pplEN) d.Sf["MA"+n].value = Math.round(parseInt(d.Sf.MA.value,10)*c/sDI);
}); });
if (pplEN) d.Sf.MA.value = sumMA; // update global ABL if using PPL
// update total led count // update total led count
gId("lc").textContent = sLC; gId("lc").textContent = sLC;
gId("pc").textContent = (sLC == sPC) ? "":"(" + sPC + " physical)"; gId("pc").textContent = (sLC == sPC) ? "":"(" + sPC + " physical)";
@ -336,7 +348,6 @@
gId('ledwarning').style.color = (maxLC > Math.max(maxPB,800) || bquot > 100) ? 'red':'orange'; gId('ledwarning').style.color = (maxLC > Math.max(maxPB,800) || bquot > 100) ? 'red':'orange';
gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>ERROR: Using over ${maxM}B!</b>)` : "") : "800 LEDs per output"; gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>ERROR: Using over ${maxM}B!</b>)` : "") : "800 LEDs per output";
// calculate power // calculate power
if (pplEN) d.Sf.MA.value = sumMA;
gId('ampwarning').style.display = (parseInt(d.Sf.MA.value,10) > 7200) ? 'inline':'none'; gId('ampwarning').style.display = (parseInt(d.Sf.MA.value,10) > 7200) ? 'inline':'none';
var val = Math.ceil((100 + busMA)/500)/2; var val = Math.ceil((100 + busMA)/500)/2;
val = (val > 5) ? Math.ceil(val) : val; val = (val > 5) ? Math.ceil(val) : val;
@ -409,7 +420,7 @@ mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();">
<option value="0">Custom</option> <option value="0">Custom</option>
</select><br> </select><br>
<div id="LAdis${i}" style="display: none;">max. mA/LED: <input name="LA${i}" type="number" min="1" max="254" oninput="UI()"> mA<br></div> <div id="LAdis${i}" style="display: none;">max. mA/LED: <input name="LA${i}" type="number" min="1" max="254" oninput="UI()"> mA<br></div>
<div id="PSU${i}">PSU: <input name="MA${i}" type="number" class="xl" min="250" max="65000" oninput="UI()"> mA<br></div> <div id="PSU${i}">PSU: <input name="MA${i}" type="number" class="xl" min="250" max="65000" oninput="UI()" value="250"> mA<br></div>
</div> </div>
<div id="co${i}" style="display:inline">Color Order: <div id="co${i}" style="display:inline">Color Order:
<select name="CO${i}"> <select name="CO${i}">
@ -445,7 +456,10 @@ mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();">
gId("+").style.display = (i<maxB+maxV-1) ? "inline":"none"; gId("+").style.display = (i<maxB+maxV-1) ? "inline":"none";
gId("-").style.display = (i>0) ? "inline":"none"; gId("-").style.display = (i>0) ? "inline":"none";
if (!init) UI(); if (!init) {
enPPL();
UI();
}
} }
function addCOM(start=0,len=1,co=0) { function addCOM(start=0,len=1,co=0) {
@ -750,7 +764,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
<i>Automatically limits brightness to stay close to the limit.<br> <i>Automatically limits brightness to stay close to the limit.<br>
Keep at &lt;1A if poweing LEDs directly from the ESP 5V pin!<br> Keep at &lt;1A if poweing LEDs directly from the ESP 5V pin!<br>
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i> Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i>
Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br> <div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br></div>
Use per-output limiter: <input type="checkbox" name="PPL" onchange="enPPL()"><br> Use per-output limiter: <input type="checkbox" name="PPL" onchange="enPPL()"><br>
<div id="ppldis" style="display:none;"> <div id="ppldis" style="display:none;">
<i>Make sure you enter correct values in each LED output.<br> <i>Make sure you enter correct values in each LED output.<br>

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -643,8 +643,8 @@ void decodeIRJson(uint32_t code)
// this may fail for two reasons: ir.json does not exist or IR code not found // this may fail for two reasons: ir.json does not exist or IR code not found
// if the IR code is not found readObjectFromFile() will clean() doc JSON document // if the IR code is not found readObjectFromFile() will clean() doc JSON document
// so we can differentiate between the two // so we can differentiate between the two
readObjectFromFile("/ir.json", objKey, &doc); readObjectFromFile("/ir.json", objKey, pDoc);
fdo = doc.as<JsonObject>(); fdo = pDoc->as<JsonObject>();
lastValidCode = 0; lastValidCode = 0;
if (fdo.isNull()) { if (fdo.isNull()) {
//the received code does not exist //the received code does not exist

View File

@ -606,9 +606,9 @@ void serializeInfo(JsonObject root)
JsonObject leds = root.createNestedObject("leds"); JsonObject leds = root.createNestedObject("leds");
leds[F("count")] = strip.getLengthTotal(); leds[F("count")] = strip.getLengthTotal();
leds[F("pwr")] = strip.currentMilliamps; leds[F("pwr")] = BusManager::currentMilliamps();
leds["fps"] = strip.getFps(); leds["fps"] = strip.getFps();
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; leds[F("maxpwr")] = BusManager::currentMilliamps()>0 ? BusManager::ablMilliampsMax() : 0;
leds[F("maxseg")] = strip.getMaxSegments(); leds[F("maxseg")] = strip.getMaxSegments();
//leds[F("actseg")] = strip.getActiveSegmentsNum(); //leds[F("actseg")] = strip.getActiveSegmentsNum();
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config //leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
@ -1056,7 +1056,7 @@ void serveJson(AsyncWebServerRequest* request)
servingClient = false; servingClient = false;
return; return;
} }
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary AsyncJsonResponse *response = new AsyncJsonResponse(pDoc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
JsonVariant lDoc = response->getRoot(); JsonVariant lDoc = response->getRoot();

View File

@ -109,8 +109,8 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
return; return;
} }
if (payloadStr[0] == '{') { //JSON API if (payloadStr[0] == '{') { //JSON API
deserializeJson(doc, payloadStr); deserializeJson(*pDoc, payloadStr);
deserializeState(doc.as<JsonObject>()); deserializeState(pDoc->as<JsonObject>());
} else { //HTTP API } else { //HTTP API
String apireq = "win"; apireq += '&'; // reduce flash string usage String apireq = "win"; apireq += '&'; // reduce flash string usage
apireq += payloadStr; apireq += payloadStr;

View File

@ -238,7 +238,7 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag)
// Check if supplied GPIO is ok to use // Check if supplied GPIO is ok to use
bool PinManagerClass::isPinOk(byte gpio, bool output) bool PinManagerClass::isPinOk(byte gpio, bool output)
{ {
#ifdef ESP32 #ifdef ARDUINO_ARCH_ESP32
if (digitalPinIsValid(gpio)) { if (digitalPinIsValid(gpio)) {
#if defined(CONFIG_IDF_TARGET_ESP32C3) #if defined(CONFIG_IDF_TARGET_ESP32C3)
// strapping pins: 2, 8, & 9 // strapping pins: 2, 8, & 9
@ -257,6 +257,9 @@ bool PinManagerClass::isPinOk(byte gpio, bool output)
// GPIO46 is input only and pulled down // GPIO46 is input only and pulled down
#else #else
if (gpio > 5 && gpio < 12) return false; //SPI flash pins if (gpio > 5 && gpio < 12) return false; //SPI flash pins
#ifdef BOARD_HAS_PSRAM
if (gpio == 16 || gpio == 17) return false; //PSRAM pins
#endif
#endif #endif
if (output) return digitalPinCanOutput(gpio); if (output) return digitalPinCanOutput(gpio);
else return true; else return true;

View File

@ -29,7 +29,7 @@ static void doSaveState() {
if (!requestJSONBufferLock(10)) return; // will set fileDoc if (!requestJSONBufferLock(10)) return; // will set fileDoc
initPresetsFile(); // just in case if someone deleted presets.json using /edit initPresetsFile(); // just in case if someone deleted presets.json using /edit
JsonObject sObj = doc.to<JsonObject>(); JsonObject sObj = pDoc->to<JsonObject>();
DEBUG_PRINTLN(F("Serialize current state")); DEBUG_PRINTLN(F("Serialize current state"));
if (playlistSave) { if (playlistSave) {
@ -44,7 +44,7 @@ static void doSaveState() {
/* /*
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
DEBUG_PRINTLN(F("Serialized preset")); DEBUG_PRINTLN(F("Serialized preset"));
serializeJson(doc,Serial); serializeJson(*pDoc,Serial);
DEBUG_PRINTLN(); DEBUG_PRINTLN();
#endif #endif
*/ */
@ -85,9 +85,9 @@ bool getPresetName(byte index, String& name)
{ {
if (!requestJSONBufferLock(9)) return false; if (!requestJSONBufferLock(9)) return false;
bool presetExists = false; bool presetExists = false;
if (readObjectFromFileUsingId(getFileName(), index, &doc)) if (readObjectFromFileUsingId(getFileName(), index, pDoc))
{ {
JsonObject fdo = doc.as<JsonObject>(); JsonObject fdo = pDoc->as<JsonObject>();
if (fdo["n"]) { if (fdo["n"]) {
name = (const char*)(fdo["n"]); name = (const char*)(fdo["n"]);
presetExists = true; presetExists = true;

View File

@ -123,8 +123,8 @@ static bool remoteJson(int button)
sprintf_P(objKey, PSTR("\"%d\":"), button); sprintf_P(objKey, PSTR("\"%d\":"), button);
// attempt to read command from remote.json // attempt to read command from remote.json
readObjectFromFile("/remote.json", objKey, &doc); readObjectFromFile("/remote.json", objKey, pDoc);
JsonObject fdo = doc.as<JsonObject>(); JsonObject fdo = pDoc->as<JsonObject>();
if (fdo.isNull()) { if (fdo.isNull()) {
// the received button does not exist // the received button does not exist
if (!WLED_FS.exists("/remote.json")) errorFlag = ERR_FS_RMLOAD; //warn if file itself doesn't exist if (!WLED_FS.exists("/remote.json")) errorFlag = ERR_FS_RMLOAD; //warn if file itself doesn't exist

View File

@ -99,8 +99,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
uint16_t length, start, maMax; uint16_t length, start, maMax;
uint8_t pins[5] = {255, 255, 255, 255, 255}; uint8_t pins[5] = {255, 255, 255, 255, 255};
strip.ablMilliampsMax = request->arg(F("MA")).toInt(); uint16_t ablMilliampsMax = request->arg(F("MA")).toInt();
//strip.milliampsPerLed = request->arg(F("LA")).toInt(); BusManager::setMilliampsMax(ablMilliampsMax);
autoSegments = request->hasArg(F("MS")); autoSegments = request->hasArg(F("MS"));
correctWB = request->hasArg(F("CCT")); correctWB = request->hasArg(F("CCT"));
@ -197,7 +197,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
com.add(start, length, colorOrder); com.add(start, length, colorOrder);
} }
} }
busses.updateColorOrderMap(com); BusManager::updateColorOrderMap(com);
// upate other pins // upate other pins
int hw_ir_pin = request->arg(F("IR")).toInt(); int hw_ir_pin = request->arg(F("IR")).toInt();
@ -626,7 +626,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
} }
} }
JsonObject um = doc.createNestedObject("um"); JsonObject um = pDoc->createNestedObject("um");
size_t args = request->args(); size_t args = request->args();
uint16_t j=0; uint16_t j=0;

View File

@ -666,8 +666,8 @@ void handleNotifications()
apireq += (char*)udpIn; apireq += (char*)udpIn;
handleSet(nullptr, apireq); handleSet(nullptr, apireq);
} else if (udpIn[0] == '{') { //JSON API } else if (udpIn[0] == '{') { //JSON API
DeserializationError error = deserializeJson(doc, udpIn); DeserializationError error = deserializeJson(*pDoc, udpIn);
JsonObject root = doc.as<JsonObject>(); JsonObject root = pDoc->as<JsonObject>();
if (!error && !root.isNull()) deserializeState(root); if (!error && !root.isNull()) deserializeState(root);
} }
releaseJSONBufferLock(); releaseJSONBufferLock();

View File

@ -209,6 +209,10 @@ bool isAsterisksOnly(const char* str, byte maxLen)
//threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994 //threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994
bool requestJSONBufferLock(uint8_t module) bool requestJSONBufferLock(uint8_t module)
{ {
if (pDoc == nullptr) {
DEBUG_PRINTLN(F("ERROR: JSON buffer not allocated!"));
return false;
}
unsigned long now = millis(); unsigned long now = millis();
while (jsonBufferLock && millis()-now < 1000) delay(1); // wait for a second for buffer lock while (jsonBufferLock && millis()-now < 1000) delay(1); // wait for a second for buffer lock
@ -224,8 +228,8 @@ bool requestJSONBufferLock(uint8_t module)
DEBUG_PRINT(F("JSON buffer locked. (")); DEBUG_PRINT(F("JSON buffer locked. ("));
DEBUG_PRINT(jsonBufferLock); DEBUG_PRINT(jsonBufferLock);
DEBUG_PRINTLN(")"); DEBUG_PRINTLN(")");
fileDoc = &doc; // used for applying presets (presets.cpp) fileDoc = pDoc; // used for applying presets (presets.cpp)
doc.clear(); pDoc->clear();
return true; return true;
} }
@ -556,11 +560,12 @@ void enumerateLedmaps() {
#ifndef ESP8266 #ifndef ESP8266
if (requestJSONBufferLock(21)) { if (requestJSONBufferLock(21)) {
if (readObjectFromFile(fileName, nullptr, &doc)) { if (readObjectFromFile(fileName, nullptr, pDoc)) {
size_t len = 0; size_t len = 0;
if (!doc["n"].isNull()) { JsonObject root = pDoc->as<JsonObject>();
if (!root["n"].isNull()) {
// name field exists // name field exists
const char *name = doc["n"].as<const char*>(); const char *name = root["n"].as<const char*>();
if (name != nullptr) len = strlen(name); if (name != nullptr) len = strlen(name);
if (len > 0 && len < 33) { if (len > 0 && len < 33) {
ledmapNames[i-1] = new char[len+1]; ledmapNames[i-1] = new char[len+1];

View File

@ -157,7 +157,7 @@ void WLED::loop()
doInitBusses = false; doInitBusses = false;
DEBUG_PRINTLN(F("Re-init busses.")); DEBUG_PRINTLN(F("Re-init busses."));
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
busses.removeAll(); BusManager::removeAll();
uint32_t mem = 0, globalBufMem = 0; uint32_t mem = 0, globalBufMem = 0;
uint16_t maxlen = 0; uint16_t maxlen = 0;
for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
@ -168,7 +168,7 @@ void WLED::loop()
globalBufMem = maxlen * 4; globalBufMem = maxlen * 4;
} }
if (mem + globalBufMem <= MAX_LED_MEMORY) { if (mem + globalBufMem <= MAX_LED_MEMORY) {
busses.add(*busConfigs[i]); BusManager::add(*busConfigs[i]);
} }
delete busConfigs[i]; busConfigs[i] = nullptr; delete busConfigs[i]; busConfigs[i] = nullptr;
} }
@ -346,6 +346,11 @@ void WLED::setup()
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
/*
* The following code is obsolete as PinManager::isPinOK() will return false for reserved GPIO.
* Additionally xml.cpp will inform UI about reserved GPIO.
*
#if defined(CONFIG_IDF_TARGET_ESP32S3) #if defined(CONFIG_IDF_TARGET_ESP32S3)
// S3: reserve GPIO 33-37 for "octal" PSRAM // S3: reserve GPIO 33-37 for "octal" PSRAM
managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} }; managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} };
@ -363,12 +368,17 @@ void WLED::setup()
managed_pin_type pins[] = { {16, true}, {17, true} }; managed_pin_type pins[] = { {16, true}, {17, true} };
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
#endif #endif
*/
#if defined(WLED_USE_PSRAM) #if defined(WLED_USE_PSRAM)
pDoc = new PSRAMDynamicJsonDocument(2*JSON_BUFFER_SIZE);
if (!pDoc) pDoc = new PSRAMDynamicJsonDocument(JSON_BUFFER_SIZE); // falback if double sized buffer could not be allocated
// if the above still fails requestJsonBufferLock() will always return false preventing crashes
if (psramFound()) { if (psramFound()) {
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
} }
#else #else
if (!pDoc) pDoc = &gDoc; // just in case ... (it should be globally assigned)
DEBUG_PRINTLN(F("PSRAM not used.")); DEBUG_PRINTLN(F("PSRAM not used."));
#endif #endif
#endif #endif
@ -960,7 +970,7 @@ void WLED::handleStatusLED()
#if STATUSLED>=0 #if STATUSLED>=0
digitalWrite(STATUSLED, ledStatusState); digitalWrite(STATUSLED, ledStatusState);
#else #else
busses.setStatusPixel(ledStatusState ? c : 0); BusManager::setStatusPixel(ledStatusState ? c : 0);
#endif #endif
} }
} else { } else {
@ -971,7 +981,7 @@ void WLED::handleStatusLED()
digitalWrite(STATUSLED, LOW); digitalWrite(STATUSLED, LOW);
#endif #endif
#else #else
busses.setStatusPixel(0); BusManager::setStatusPixel(0);
#endif #endif
} }
} }

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2312270 #define VERSION 2401010
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -759,7 +759,12 @@ WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN);
#endif #endif
// global ArduinoJson buffer // global ArduinoJson buffer
WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> doc; #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
WLED_GLOBAL JsonDocument *pDoc _INIT(nullptr);
#else
WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> gDoc;
WLED_GLOBAL JsonDocument *pDoc _INIT(&gDoc);
#endif
WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0); WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0);
// enable additional debug output // enable additional debug output

View File

@ -99,7 +99,7 @@ void loadSettingsFromEEPROM()
bool skipFirst = EEPROM.read(2204); bool skipFirst = EEPROM.read(2204);
bool reversed = EEPROM.read(252); bool reversed = EEPROM.read(252);
BusConfig bc = BusConfig(EEPROM.read(372) ? TYPE_SK6812_RGBW : TYPE_WS2812_RGB, pins, 0, length, colorOrder, reversed, skipFirst); BusConfig bc = BusConfig(EEPROM.read(372) ? TYPE_SK6812_RGBW : TYPE_WS2812_RGB, pins, 0, length, colorOrder, reversed, skipFirst);
busses.add(bc); BusManager::add(bc);
notifyButton = EEPROM.read(230); notifyButton = EEPROM.read(230);
if (EEPROM.read(231)) udpNumRetries = 1; if (EEPROM.read(231)) udpNumRetries = 1;
@ -371,7 +371,7 @@ void deEEP() {
DEBUGFS_PRINTLN(F("Allocating saving buffer for dEEP")); DEBUGFS_PRINTLN(F("Allocating saving buffer for dEEP"));
if (!requestJSONBufferLock(8)) return; if (!requestJSONBufferLock(8)) return;
JsonObject sObj = doc.to<JsonObject>(); JsonObject sObj = pDoc->to<JsonObject>();
sObj.createNestedObject("0"); sObj.createNestedObject("0");
EEPROM.begin(EEPSIZE); EEPROM.begin(EEPSIZE);
@ -448,7 +448,7 @@ void deEEP() {
releaseJSONBufferLock(); releaseJSONBufferLock();
return; return;
} }
serializeJson(doc, f); serializeJson(*pDoc, f);
f.close(); f.close();
releaseJSONBufferLock(); releaseJSONBufferLock();

View File

@ -115,21 +115,21 @@ void handleSerial()
bool verboseResponse = false; bool verboseResponse = false;
if (!requestJSONBufferLock(16)) return; if (!requestJSONBufferLock(16)) return;
Serial.setTimeout(100); Serial.setTimeout(100);
DeserializationError error = deserializeJson(doc, Serial); DeserializationError error = deserializeJson(*pDoc, Serial);
if (error) { if (error) {
releaseJSONBufferLock(); releaseJSONBufferLock();
return; return;
} }
verboseResponse = deserializeState(doc.as<JsonObject>()); verboseResponse = deserializeState(pDoc->as<JsonObject>());
//only send response if TX pin is unused for other purposes //only send response if TX pin is unused for other purposes
if (verboseResponse && (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut)) { if (verboseResponse && (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut)) {
doc.clear(); pDoc->clear();
JsonObject state = doc.createNestedObject("state"); JsonObject state = pDoc->createNestedObject("state");
serializeState(state); serializeState(state);
JsonObject info = doc.createNestedObject("info"); JsonObject info = pDoc->createNestedObject("info");
serializeInfo(info); serializeInfo(info);
serializeJson(doc, Serial); serializeJson(*pDoc, Serial);
Serial.println(); Serial.println();
} }
releaseJSONBufferLock(); releaseJSONBufferLock();

View File

@ -180,8 +180,8 @@ void initServer()
if (!requestJSONBufferLock(14)) return; if (!requestJSONBufferLock(14)) return;
DeserializationError error = deserializeJson(doc, (uint8_t*)(request->_tempObject)); DeserializationError error = deserializeJson(*pDoc, (uint8_t*)(request->_tempObject));
JsonObject root = doc.as<JsonObject>(); JsonObject root = pDoc->as<JsonObject>();
if (error || root.isNull()) { if (error || root.isNull()) {
releaseJSONBufferLock(); releaseJSONBufferLock();
serveJsonError(request, 400, ERR_JSON); serveJsonError(request, 400, ERR_JSON);

View File

@ -38,8 +38,8 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
bool verboseResponse = false; bool verboseResponse = false;
if (!requestJSONBufferLock(11)) return; if (!requestJSONBufferLock(11)) return;
DeserializationError error = deserializeJson(doc, data, len); DeserializationError error = deserializeJson(*pDoc, data, len);
JsonObject root = doc.as<JsonObject>(); JsonObject root = pDoc->as<JsonObject>();
if (error || root.isNull()) { if (error || root.isNull()) {
releaseJSONBufferLock(); releaseJSONBufferLock();
return; return;
@ -103,13 +103,13 @@ void sendDataWs(AsyncWebSocketClient * client)
if (!requestJSONBufferLock(12)) return; if (!requestJSONBufferLock(12)) return;
JsonObject state = doc.createNestedObject("state"); JsonObject state = pDoc->createNestedObject("state");
serializeState(state); serializeState(state);
JsonObject info = doc.createNestedObject("info"); JsonObject info = pDoc->createNestedObject("info");
serializeInfo(info); serializeInfo(info);
size_t len = measureJson(doc); size_t len = measureJson(*pDoc);
DEBUG_PRINTF("JSON buffer size: %u for WS request (%u).\n", doc.memoryUsage(), len); DEBUG_PRINTF("JSON buffer size: %u for WS request (%u).\n", pDoc->memoryUsage(), len);
size_t heap1 = ESP.getFreeHeap(); size_t heap1 = ESP.getFreeHeap();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
@ -136,7 +136,7 @@ void sendDataWs(AsyncWebSocketClient * client)
} }
buffer->lock(); buffer->lock();
serializeJson(doc, (char *)buffer->get(), len); serializeJson(*pDoc, (char *)buffer->get(), len);
DEBUG_PRINT(F("Sending WS data ")); DEBUG_PRINT(F("Sending WS data "));
if (client) { if (client) {

View File

@ -133,7 +133,7 @@ void appendGPIOinfo() {
// usermod pin reservations will become unnecessary when settings pages will read cfg.json directly // usermod pin reservations will become unnecessary when settings pages will read cfg.json directly
if (requestJSONBufferLock(6)) { if (requestJSONBufferLock(6)) {
// if we can't allocate JSON buffer ignore usermod pins // if we can't allocate JSON buffer ignore usermod pins
JsonObject mods = doc.createNestedObject(F("um")); JsonObject mods = pDoc->createNestedObject(F("um"));
usermods.addToConfig(mods); usermods.addToConfig(mods);
if (!mods.isNull()) fillUMPins(mods); if (!mods.isNull()) fillUMPins(mods);
releaseJSONBufferLock(); releaseJSONBufferLock();
@ -356,8 +356,8 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("LD"),useGlobalLedBuffer); sappend('c',SET_F("LD"),useGlobalLedBuffer);
uint16_t sumMa = 0; uint16_t sumMa = 0;
for (uint8_t s=0; s < busses.getNumBusses(); s++) { for (uint8_t s=0; s < BusManager::getNumBusses(); s++) {
Bus* bus = busses.getBus(s); Bus* bus = BusManager::getBus(s);
if (bus == nullptr) continue; if (bus == nullptr) continue;
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
@ -413,22 +413,13 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',ma,bus->getMaxCurrent()); sappend('v',ma,bus->getMaxCurrent());
sumMa += bus->getMaxCurrent(); sumMa += bus->getMaxCurrent();
} }
sappend('c',SET_F("PPL"),(sumMa>0 && abs(sumMa - strip.ablMilliampsMax)>2)); // approxiamte detection if per-output limiter is enabled sappend('v',SET_F("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa);
sappend('v',SET_F("MA"),strip.ablMilliampsMax); sappend('c',SET_F("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0);
/*
sappend('v',SET_F("LA"),strip.milliampsPerLed);
if (strip.currentMilliamps)
{
sappends('m',SET_F("(\"pow\")[0]"),(char*)"");
olen -= 2; //delete ";
oappendi(strip.currentMilliamps);
oappend(SET_F("mA\";"));
}
*/
oappend(SET_F("resetCOM(")); oappend(SET_F("resetCOM("));
oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10));
oappend(SET_F(");")); oappend(SET_F(");"));
const ColorOrderMap& com = busses.getColorOrderMap(); const ColorOrderMap& com = BusManager::getColorOrderMap();
for (uint8_t s=0; s < com.count(); s++) { for (uint8_t s=0; s < com.count(); s++) {
const ColorOrderMapEntry* entry = com.get(s); const ColorOrderMapEntry* entry = com.get(s);
if (entry == nullptr) break; if (entry == nullptr) break;