Vectors & dynamic loadJS.

- Segments
- Modes

NOTE: crashes ESP if effect is running while deleting segment.
This commit is contained in:
Blaz Kristan 2022-07-17 15:58:41 +02:00
parent 8f72e0ab83
commit 6c6849d8d7
31 changed files with 3189 additions and 2884 deletions

View File

@ -263,120 +263,60 @@ writeChunks(
name: "PAGE_settings", name: "PAGE_settings",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=0\"></script>"
)
}, },
{ {
file: "settings_wifi.htm", file: "settings_wifi.htm",
name: "PAGE_settings_wifi", name: "PAGE_settings_wifi",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=1\"></script>"
)
}, },
{ {
file: "settings_leds.htm", file: "settings_leds.htm",
name: "PAGE_settings_leds", name: "PAGE_settings_leds",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=2\"></script>"
)
}, },
{ {
file: "settings_dmx.htm", file: "settings_dmx.htm",
name: "PAGE_settings_dmx", name: "PAGE_settings_dmx",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=7\"></script>"
)
}, },
{ {
file: "settings_ui.htm", file: "settings_ui.htm",
name: "PAGE_settings_ui", name: "PAGE_settings_ui",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=3\"></script>"
)
}, },
{ {
file: "settings_sync.htm", file: "settings_sync.htm",
name: "PAGE_settings_sync", name: "PAGE_settings_sync",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=4\"></script>"
)
}, },
{ {
file: "settings_time.htm", file: "settings_time.htm",
name: "PAGE_settings_time", name: "PAGE_settings_time",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=5\"></script>"
)
}, },
{ {
file: "settings_sec.htm", file: "settings_sec.htm",
name: "PAGE_settings_sec", name: "PAGE_settings_sec",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=6\"></script>"
)
}, },
{ {
file: "settings_um.htm", file: "settings_um.htm",
name: "PAGE_settings_um", name: "PAGE_settings_um",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=8\"></script>"
)
}, },
{ {
file: "settings_2D.htm", file: "settings_2D.htm",
name: "PAGE_settings_2D", name: "PAGE_settings_2D",
method: "gzip", method: "gzip",
filter: "html-minify", filter: "html-minify",
mangle: (str) =>
str
.replace(
/function GetV().*\<\/script\>/gms,
"</script><script src=\"/settings/s.js?p=10\"></script>"
)
}, },
{ {
file: "settings_pin.htm", file: "settings_pin.htm",

View File

@ -103,25 +103,24 @@ class Animated_Staircase : public Usermod {
void updateSegments() { void updateSegments() {
mainSegmentId = strip.getMainSegmentId(); mainSegmentId = strip.getMainSegmentId();
Segment* segments = strip.getSegments(); for (int i = 0; i < strip.getActiveSegmentsNum(); i++) {
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) { Segment &seg = strip.getSegment(i);
if (!segments->isActive()) { if (!seg.isActive()) {
maxSegmentId = i - 1; maxSegmentId = i - 1;
break; break;
} }
if (i >= onIndex && i < offIndex) { if (i >= onIndex && i < offIndex) {
segments->setOption(SEG_OPTION_ON, 1, i); seg.setOption(SEG_OPTION_ON, true);
// We may need to copy mode and colors from segment 0 to make sure // We may need to copy mode and colors from segment 0 to make sure
// changes are propagated even when the config is changed during a wipe // changes are propagated even when the config is changed during a wipe
// segments->mode = mainsegment.mode; // segments->mode = mainsegment.mode;
// segments->colors[0] = mainsegment.colors[0]; // segments->colors[0] = mainsegment.colors[0];
} else { } else {
segments->setOption(SEG_OPTION_ON, 0, i); seg.setOption(SEG_OPTION_ON, false);
} }
// Always mark segments as "transitional", we are animating the staircase // Always mark segments as "transitional", we are animating the staircase
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, i); seg.setOption(SEG_OPTION_TRANSITIONAL, true);
} }
colorUpdated(CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
} }
@ -290,13 +289,13 @@ class Animated_Staircase : public Usermod {
} }
} else { } else {
// Restore segment options // Restore segment options
Segment* segments = strip.getSegments(); for (int i = 0; i < strip.getActiveSegmentsNum(); i++) {
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) { Segment &seg = strip.getSegment(i);
if (!segments->isActive()) { if (!seg.isActive()) {
maxSegmentId = i - 1; maxSegmentId = i - 1;
break; break;
} }
segments->setOption(SEG_OPTION_ON, 1, i); seg.setOption(SEG_OPTION_ON, true);
} }
colorUpdated(CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
DEBUG_PRINTLN(F("Animated Staircase disabled.")); DEBUG_PRINTLN(F("Animated Staircase disabled."));

View File

@ -528,7 +528,7 @@ public:
effectCurrent = modes_alpha_indexes[effectCurrentIndex]; effectCurrent = modes_alpha_indexes[effectCurrentIndex];
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
strip.setMode(i, effectCurrent); strip.setMode(i, effectCurrent);
@ -556,7 +556,7 @@ public:
effectSpeed = max(min((increase ? effectSpeed+fadeAmount : effectSpeed-fadeAmount), 255), 0); effectSpeed = max(min((increase ? effectSpeed+fadeAmount : effectSpeed-fadeAmount), 255), 0);
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.speed = effectSpeed; seg.speed = effectSpeed;
@ -584,7 +584,7 @@ public:
effectIntensity = max(min((increase ? effectIntensity+fadeAmount : effectIntensity-fadeAmount), 255), 0); effectIntensity = max(min((increase ? effectIntensity+fadeAmount : effectIntensity-fadeAmount), 255), 0);
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.intensity = effectIntensity; seg.intensity = effectIntensity;
@ -613,22 +613,23 @@ public:
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
uint8_t id = strip.getFirstSelectedSegId(); uint8_t id = strip.getFirstSelectedSegId();
Segment& sid = strip.getSegment(id);
switch (par) { switch (par) {
case 3: val = strip.getSegment(id).custom3 = max(min((increase ? strip.getSegment(id).custom3+fadeAmount : strip.getSegment(id).custom3-fadeAmount), 255), 0); break; case 3: val = sid.custom3 = max(min((increase ? sid.custom3+fadeAmount : sid.custom3-fadeAmount), 255), 0); break;
case 2: val = strip.getSegment(id).custom2 = max(min((increase ? strip.getSegment(id).custom2+fadeAmount : strip.getSegment(id).custom2-fadeAmount), 255), 0); break; case 2: val = sid.custom2 = max(min((increase ? sid.custom2+fadeAmount : sid.custom2-fadeAmount), 255), 0); break;
default: val = strip.getSegment(id).custom1 = max(min((increase ? strip.getSegment(id).custom1+fadeAmount : strip.getSegment(id).custom1-fadeAmount), 255), 0); break; default: val = sid.custom1 = max(min((increase ? sid.custom1+fadeAmount : sid.custom1-fadeAmount), 255), 0); break;
} }
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || i == id) continue; if (!seg.isActive() || i == id) continue;
switch (par) { switch (par) {
case 3: strip.getSegment(i).custom3 = strip.getSegment(id).custom3; break; case 3: seg.custom3 = sid.custom3; break;
case 2: strip.getSegment(i).custom2 = strip.getSegment(id).custom2; break; case 2: seg.custom2 = sid.custom2; break;
default: strip.getSegment(i).custom1 = strip.getSegment(id).custom1; break; default: seg.custom1 = sid.custom1; break;
} }
} }
} else { } else {
Segment& seg = strip.getSegment(strip.getMainSegmentId()); Segment& seg = strip.getMainSegment();
switch (par) { switch (par) {
case 3: val = seg.custom3 = max(min((increase ? seg.custom3+fadeAmount : seg.custom3-fadeAmount), 255), 0); break; case 3: val = seg.custom3 = max(min((increase ? seg.custom3+fadeAmount : seg.custom3-fadeAmount), 255), 0); break;
case 2: val = seg.custom2 = max(min((increase ? seg.custom2+fadeAmount : seg.custom2-fadeAmount), 255), 0); break; case 2: val = seg.custom2 = max(min((increase ? seg.custom2+fadeAmount : seg.custom2-fadeAmount), 255), 0); break;
@ -657,7 +658,7 @@ public:
effectPalette = palettes_alpha_indexes[effectPaletteIndex]; effectPalette = palettes_alpha_indexes[effectPaletteIndex];
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.palette = effectPalette; seg.palette = effectPalette;
@ -686,7 +687,7 @@ public:
colorHStoRGB(currentHue1*256, currentSat1, col); colorHStoRGB(currentHue1*256, currentSat1, col);
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]); seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
@ -715,7 +716,7 @@ public:
currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0); currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0);
colorHStoRGB(currentHue1*256, currentSat1, col); colorHStoRGB(currentHue1*256, currentSat1, col);
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]); seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
@ -775,7 +776,7 @@ public:
#endif #endif
currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0); currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0);
// if (applyToAll) { // if (applyToAll) {
for (byte i=0; i<strip.getMaxSegments(); i++) { for (byte i=0; i<strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.setCCT(currentCCT); seg.setCCT(currentCCT);

View File

@ -3134,8 +3134,8 @@ typedef struct particle {
uint16_t mode_starburst(void) { uint16_t mode_starburst(void) {
uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
uint8_t segs = strip.getActiveSegmentsNum(); uint8_t segs = strip.getActiveSegmentsNum();
if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs if (segs <= (strip.getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs if (segs <= (strip.getMaxSegments() /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg
uint8_t numStars = 1 + (SEGLEN >> 3); uint8_t numStars = 1 + (SEGLEN >> 3);
@ -3257,8 +3257,8 @@ uint16_t mode_exploding_fireworks(void)
//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
uint8_t segs = strip.getActiveSegmentsNum(); uint8_t segs = strip.getActiveSegmentsNum();
if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs if (segs <= (strip.getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs if (segs <= (strip.getMaxSegments() /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg
uint16_t numSparks = min(2 + ((rows*cols) >> 1), maxSparks); uint16_t numSparks = min(2 + ((rows*cols) >> 1), maxSparks);
@ -7667,12 +7667,21 @@ static const char *_data_FX_MODE_2DAKEMI PROGMEM = "2D Akemi@Color speed,Dance;H
static const char *_data_RESERVED PROGMEM = "Reserved"; static const char *_data_RESERVED PROGMEM = "Reserved";
void WS2812FX::addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name) { void WS2812FX::addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name) {
/*
if (id == 255) { for (int i=1; i<_modeCount; i++) if (_mode[i] == &mode_static) { id = i; break; } } // find empty slot if (id == 255) { for (int i=1; i<_modeCount; i++) if (_mode[i] == &mode_static) { id = i; break; } } // find empty slot
if (id < _modeCount) { if (id < _modeCount) {
if (_mode[id] != &mode_static) return; // do not overwrite alerady added effect if (_mode[id] != &mode_static) return; // do not overwrite alerady added effect
_mode[id] = mode_fn; _mode[id] = mode_fn;
_modeData[id] = mode_name; _modeData[id] = mode_name;
} }
*/
if (id >= _mode.size()) {
_mode.push_back(mode_fn);
_modeData.push_back(mode_name);
} else {
_mode.insert(_mode.begin()+id, mode_fn);
_modeData.insert(_modeData.begin()+id, mode_name);
}
} }
void WS2812FX::setupEffectData() { void WS2812FX::setupEffectData() {

View File

@ -27,6 +27,8 @@
#ifndef WS2812FX_h #ifndef WS2812FX_h
#define WS2812FX_h #define WS2812FX_h
#include <vector>
#include "const.h" #include "const.h"
#define FASTLED_INTERNAL //remove annoying pragma messages #define FASTLED_INTERNAL //remove annoying pragma messages
@ -68,29 +70,27 @@ uint32_t color_add(uint32_t,uint32_t);
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 16
/* How many color transitions can run at once */
#define MAX_NUM_TRANSITIONS 8
/* How much data bytes all segments combined may allocate */ /* How much data bytes all segments combined may allocate */
#define MAX_SEGMENT_DATA 4096 #define MAX_SEGMENT_DATA 4096
#else #else
#ifndef MAX_NUM_SEGMENTS #ifndef MAX_NUM_SEGMENTS
#define MAX_NUM_SEGMENTS 32 #define MAX_NUM_SEGMENTS 32
#endif #endif
#define MAX_NUM_TRANSITIONS 24
#define MAX_SEGMENT_DATA 20480 #define MAX_SEGMENT_DATA 20480
#endif #endif
/* How much data bytes each segment should max allocate to leave enough space for other segments, /* How much data bytes each segment should max allocate to leave enough space for other segments,
assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */ assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */
#define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / MAX_NUM_SEGMENTS) #define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / strip.getMaxSegments())
#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) #define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15)
#define NUM_COLORS 3 /* number of colors per segment */ #define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT strip._segments[strip.getCurrSegmentId()] #define SEGMENT strip._segments[strip.getCurrSegmentId()]
#define SEGENV strip._segments[strip.getCurrSegmentId()].runtime #define SEGENV strip._segments[strip.getCurrSegmentId()]
#define SEGCOLOR(x) strip.segColor(x) //#define SEGCOLOR(x) strip._segments[s//trip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x])
//#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength() //#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength()
#define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */
#define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */ #define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */
#define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN) #define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
@ -362,53 +362,9 @@ uint32_t color_add(uint32_t,uint32_t);
#define MODE_COUNT 185 #define MODE_COUNT 185
#endif #endif
struct Segment; // segment, 68 (92 in memory) bytes
typedef struct Segment {
// color transitions public:
typedef struct ColorTransition { // 20 bytes
uint32_t colorOld[NUM_COLORS];
uint8_t briOld;
uint8_t cctOld;
uint32_t transitionStart;
uint16_t transitionDur;
void startTransition(Segment *seg, uint16_t dur); // transition has to start before actual segment values change
void handleTransition(Segment *seg, uint8_t &newBri, uint8_t &newCct, uint32_t *newCol);
uint16_t progress(); //transition progression between 0-65535
uint8_t currentBri(uint8_t briNew, bool useCct = false);
uint32_t currentColor(uint8_t slot, uint32_t colorNew) {
return color_blend(colorOld[slot], colorNew, progress(), true);
}
} color_transition;
// segment runtime parameters
typedef struct Segmentruntime { // 23 (24 in memory) bytes
unsigned long next_time; // millis() of next update
uint32_t step; // custom "step" var
uint32_t call; // call counter
uint16_t aux0; // custom var
uint16_t aux1; // custom var
byte* data = nullptr;
bool allocateData(uint16_t len);
void deallocateData();
void resetIfRequired();
/**
* Flags that before the next effect is calculated,
* the internal segment state should be reset.
* Call resetIfRequired before calling the next effect function.
* Safe to call from interrupts and network requests.
*/
inline void markForReset() { _requiresReset = true; }
private:
uint16_t _dataLen = 0;
bool _requiresReset = false;
} segmentruntime;
// segment parameters
typedef struct Segment { // 40 (44 in memory) bytes
uint16_t start; // start index / start X coordinate 2D (left) uint16_t start; // start index / start X coordinate 2D (left)
uint16_t stop; // stop index / stop X coordinate 2D (right); segment is invalid if stop == 0 uint16_t stop; // stop index / stop X coordinate 2D (right); segment is invalid if stop == 0
uint16_t offset; uint16_t offset;
@ -416,18 +372,110 @@ typedef struct Segment { // 40 (44 in memory) bytes
uint8_t intensity; uint8_t intensity;
uint8_t palette; uint8_t palette;
uint8_t mode; uint8_t mode;
union {
uint16_t options; //bit pattern: msb first: [transposed mirrorY reverseY] transitional (tbd) paused needspixelstate mirrored on reverse selected uint16_t options; //bit pattern: msb first: [transposed mirrorY reverseY] transitional (tbd) paused needspixelstate mirrored on reverse selected
struct {
uint16_t selected:1; // 0 : selected
uint16_t reverse:1; // 1 : reversed
uint16_t on:1; // 2 : is On
uint16_t mirror:1; // 3 : mirrored
uint16_t pxs:1; // 4 : indicates that the effect does not use FRAMETIME or needs getPixelColor (?)
uint16_t freeze:1; // 5 : paused/frozen
uint16_t reset:1; // 6 : indicates that Segment runtime requires reset
uint16_t transitional:1; // 7 : transitional (there is transition occuring)
uint16_t reverse_y:1; // 8 : reversed Y (2D)
uint16_t mirror_y:1; // 9 : mirrored Y (2D)
uint16_t transpose:1; // 10 : transposed (2D, swapped X & Y)
uint16_t map1D2D:3; // 11-13 : mapping for 1D effect on 2D (0-strip, 1-expand vertically, 2-circular, 3-rectangular, 4-7 reserved)
uint16_t reserved:2; // 14-15 : reserved
};
};
uint8_t grouping, spacing; uint8_t grouping, spacing;
uint8_t opacity; uint8_t opacity;
uint32_t colors[NUM_COLORS]; uint32_t colors[NUM_COLORS];
uint8_t cct; //0==1900K, 255==10091K uint8_t cct; //0==1900K, 255==10091K
uint8_t _capabilities;
uint8_t custom1, custom2, custom3; // custom FX parameters uint8_t custom1, custom2, custom3; // custom FX parameters
uint16_t startY; // start Y coodrinate 2D (top) uint16_t startY; // start Y coodrinate 2D (top)
uint16_t stopY; // stop Y coordinate 2D (bottom) uint16_t stopY; // stop Y coordinate 2D (bottom)
char *name; char *name;
segmentruntime runtime;
color_transition transition; // runtime data
unsigned long next_time; // millis() of next update
uint32_t step; // custom "step" var
uint32_t call; // call counter
uint16_t aux0; // custom var
uint16_t aux1; // custom var
byte* data;
private:
uint8_t _capabilities;
uint16_t _dataLen;
// transition data, valid only if getOption(SEG_OPTION_TRANSITIONAL)==true
//struct Transition {
uint32_t _colorT[NUM_COLORS];
uint8_t _briT;
uint8_t _cctT;
uint32_t _start;
uint16_t _dur;
// Transition(uint16_t dur=10) : _briT(255), _cctT(127), _start(millis()), _dur(dur) {}
// Transition(uint16_t d, uint8_t b, uint8_t c, const uint32_t *o) : _briT(b), _cctT(c), _start(millis()), _dur(d) {
// for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = o[i];
// }
//} *_t; // this struct will bootloop ESP
public:
Segment(uint16_t sStart=0, uint16_t sStop=30) : start(sStart), stop(sStop) {
mode = DEFAULT_MODE;
colors[0] = DEFAULT_COLOR;
colors[1] = BLACK;
colors[2] = BLACK;
startY = 0;
stopY = 1;
speed = DEFAULT_SPEED;
intensity = DEFAULT_INTENSITY;
custom1 = DEFAULT_C1;
custom2 = DEFAULT_C2;
custom3 = DEFAULT_C3;
grouping = 1;
spacing = 0;
offset = 0;
opacity = 255;
cct = 127;
name = nullptr;
options = NO_OPTIONS;
setOption(SEG_OPTION_SELECTED, 1);
setOption(SEG_OPTION_ON, 1);
call = 0;
step = 0;
next_time = 0;
aux0 = 0;
aux1 = 0;
data = nullptr;
_dataLen = 0;
//_t = nullptr;
}
Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) {
Segment(sStartX, sStopX);
startY = sStartY;
stopY = sStopY;
}
Segment(const Segment &orig); // copy constructor
Segment(Segment &&orig) noexcept; // move constructor
~Segment() {
Serial.print(F("Destroying segment: "));
if (name) Serial.println(name); else Serial.println();
if (name) delete[] name;
//if (_t) delete _t;
deallocateData();
}
Segment& operator= (const Segment &orig); // copy assignment
Segment& operator= (Segment &&orig) noexcept; // move assignment
inline bool getOption(uint8_t n) { return ((options >> n) & 0x01); } inline bool getOption(uint8_t n) { return ((options >> n) & 0x01); }
inline bool isSelected() { return getOption(0); } inline bool isSelected() { return getOption(0); }
@ -445,6 +493,25 @@ typedef struct Segment { // 40 (44 in memory) bytes
uint8_t differs(Segment& b); uint8_t differs(Segment& b);
void refreshLightCapabilities(); void refreshLightCapabilities();
// runtime data functions
bool allocateData(uint16_t len);
void deallocateData();
void resetIfRequired();
/**
* Flags that before the next effect is calculated,
* the internal segment state should be reset.
* Call resetIfRequired before calling the next effect function.
* Safe to call from interrupts and network requests.
*/
inline void markForReset() { reset = true; } // setOption(SEG_OPTION_RESET, true)
// transition functions
void startTransition(uint16_t dur); // transition has to start before actual segment values change
void handleTransition(void);
uint16_t progress(); //transition progression between 0-65535
uint8_t currentBri(uint8_t briNew, bool useCct = false);
uint32_t currentColor(uint8_t slot, uint32_t colorNew) { return getOption(SEG_OPTION_TRANSITIONAL) /*&& !_t*/ ? color_blend(/*_t->*/_colorT[slot], colorNew, progress(), true) : colorNew; }
// 1D strip // 1D strip
uint16_t virtualLength(); uint16_t virtualLength();
void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
@ -498,12 +565,17 @@ typedef struct Segment { // 40 (44 in memory) bytes
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { drawLine(x0, y0, x1, y1, CRGB(byte(c>>16), byte(c>>8), byte(c))); } inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { drawLine(x0, y0, x1, y1, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t c) { drawCharacter(chr, x, y, w, h, CRGB(byte(c>>16), byte(c>>8), byte(c))); } inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t c) { drawCharacter(chr, x, y, w, h, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
} segment; } segment;
//static int i = sizeof(Segment);
// main "strip" class // main "strip" class
class WS2812FX { // 96 bytes class WS2812FX { // 96 bytes
typedef uint16_t (*mode_ptr)(void); // pointer to mode function typedef uint16_t (*mode_ptr)(void); // pointer to mode function
typedef void (*show_callback)(void); // pre show callback typedef void (*show_callback)(void); // pre show callback
typedef struct ModeData {
mode_ptr _fcn; // mode (effect) function
const char *_data; // mode (effect) name and its slider control data array
ModeData(uint16_t (*fcn)(void), const char *data) : _fcn(fcn), _data(data) {}
} mode_data_t;
static WS2812FX* instance; static WS2812FX* instance;
@ -511,22 +583,31 @@ class WS2812FX { // 96 bytes
WS2812FX() { WS2812FX() {
WS2812FX::instance = this; WS2812FX::instance = this;
_mode.reserve(_modeCount);
_modeData.reserve(_modeCount);
if (_mode.capacity() <= 1 || _modeData.capacity() <= 1) _modeCount = 1;
else setupEffectData();
/*
_mode = new mode_ptr[_modeCount]; _mode = new mode_ptr[_modeCount];
_modeData = new const char*[_modeCount]; _modeData = new const char*[_modeCount];
if (_mode && _modeData) setupEffectData(); if (_mode && _modeData) setupEffectData();
else _modeCount = 1; // only Solid will work else _modeCount = 1; // only Solid will work
*/
_brightness = DEFAULT_BRIGHTNESS; _brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black); currentPalette = CRGBPalette16(CRGB::Black);
targetPalette = CloudColors_p; targetPalette = CloudColors_p;
ablMilliampsMax = ABL_MILLIAMPS_DEFAULT; ablMilliampsMax = ABL_MILLIAMPS_DEFAULT;
currentMilliamps = 0; currentMilliamps = 0;
timebase = 0; timebase = 0;
resetSegments(); _usedSegmentData = 0;
//resetSegments(); // no need here
} }
~WS2812FX() { ~WS2812FX() {
delete[] _mode; //delete[] _mode;
delete[] _modeData; //delete[] _modeData;
_mode.clear();
_modeData.clear();
} }
static WS2812FX* getInstance(void) { return instance; } static WS2812FX* getInstance(void) { return instance; }
@ -542,7 +623,8 @@ class WS2812FX { // 96 bytes
setRange(uint16_t i, uint16_t i2, uint32_t col), setRange(uint16_t i, uint16_t i2, uint32_t col),
setTransitionMode(bool t), setTransitionMode(bool t),
calcGammaTable(float), calcGammaTable(float),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=0), purgeSegments(void),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1),
setMainSegmentId(uint8_t n), setMainSegmentId(uint8_t n),
restartRuntime(), restartRuntime(),
resetSegments(), resetSegments(),
@ -563,6 +645,7 @@ class WS2812FX { // 96 bytes
inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments. inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
inline void setShowCallback(show_callback cb) { _callback = cb; } inline void setShowCallback(show_callback cb) { _callback = cb; }
inline void setTransition(uint16_t t) { _transitionDur = t; } inline void setTransition(uint16_t t) { _transitionDur = t; }
inline void appendSegment(const Segment &seg = Segment()) { _segments.push_back(seg); }
inline void addUsedSegmentData(int16_t size) { _usedSegmentData += size; } inline void addUsedSegmentData(int16_t size) { _usedSegmentData += size; }
bool bool
@ -582,7 +665,7 @@ class WS2812FX { // 96 bytes
paletteBlend = 0, paletteBlend = 0,
milliampsPerLed = 55, milliampsPerLed = 55,
cctBlending = 0, cctBlending = 0,
getActiveSegmentsNum(void), //getActiveSegmentsNum(void),
getFirstSelectedSegId(void), getFirstSelectedSegId(void),
getLastActiveSegmentId(void), getLastActiveSegmentId(void),
setPixelSegment(uint8_t n), setPixelSegment(uint8_t n),
@ -590,7 +673,8 @@ class WS2812FX { // 96 bytes
gamma8_cal(uint8_t, float); gamma8_cal(uint8_t, float);
inline uint8_t getBrightness(void) { return _brightness; } inline uint8_t getBrightness(void) { return _brightness; }
inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
inline uint8_t getActiveSegmentsNum(void) { return _segments.size(); } // returns currently active (present) segments
inline uint8_t getCurrSegmentId(void) { return _segment_index; } inline uint8_t getCurrSegmentId(void) { return _segment_index; }
inline uint8_t getMainSegmentId(void) { return _mainSegment; } inline uint8_t getMainSegmentId(void) { return _mainSegment; }
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; } inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; }
@ -623,12 +707,13 @@ class WS2812FX { // 96 bytes
getModeData(uint8_t id = 0) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } getModeData(uint8_t id = 0) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
const char ** const char **
getModeDataSrc(void) { return _modeData; } getModeDataSrc(void) { return &(_modeData[0]); } // vectors use arrays for underlying data
inline Segment& getSegment(uint8_t id) { return _segments[id >= MAX_NUM_SEGMENTS ? getMainSegmentId() : id]; } //inline Segment& getSegment(uint8_t id) { return _segments[id >= getMaxSegments() ? getMainSegmentId() : id]; }
inline Segment& getSegment(uint8_t id) { return _segments[id >= _segments.size() ? getMainSegmentId() : id]; } // vectors
inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; } inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; }
inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; } inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; }
inline Segment* getSegments(void) { return _segments; } inline Segment* getSegments(void) { return &(_segments[0]); }
// 2D support (panels) // 2D support (panels)
bool bool
@ -674,25 +759,23 @@ class WS2812FX { // 96 bytes
CRGBPalette16 currentPalette; CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette; CRGBPalette16 targetPalette;
// using public variables to reduce code size increase due to inline function getSegment() (with bounds checking)
// and color transitions
uint8_t _bri_t; // used for opacity transitions uint8_t _bri_t; // used for opacity transitions
uint32_t _colors_t[3]; // used for color transitions uint32_t _colors_t[3]; // used for color transitions
uint16_t _virtualSegmentLength; uint16_t _virtualSegmentLength;
// using public array to reduce code size increase due to inline function getSegment() (with bounds checking) //segment _segments[MAX_NUM_SEGMENTS]; // SRAM footprint: 88 bytes per element
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 27 bytes per element std::vector<segment> _segments; // deleting a segment while effects play crashes ESP
// start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[], capabilities, custom 1, custom 2, custom 3
{0, 7, 0, DEFAULT_SPEED, DEFAULT_INTENSITY, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, 0, DEFAULT_C1, DEFAULT_C2, DEFAULT_C3, 0, 1}
};
friend class Segment; friend class Segment;
//size_t segSize = sizeof(Segment);
//segmentruntime _segmentruntimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element //size_t segsSize = sizeof(_segments);
//friend class Segmentruntime;
private: private:
uint16_t _length; uint16_t _length;
uint16_t _rand16seed; uint16_t _rand16seed;
uint8_t _brightness; uint8_t _brightness;
uint16_t _usedSegmentData = 0; uint16_t _usedSegmentData;
uint16_t _transitionDur = 750; uint16_t _transitionDur = 750;
uint8_t _targetFps = 42; uint8_t _targetFps = 42;
@ -705,8 +788,12 @@ class WS2812FX { // 96 bytes
_triggered; _triggered;
uint8_t _modeCount = MODE_COUNT; uint8_t _modeCount = MODE_COUNT;
mode_ptr *_mode; // SRAM footprint: 4 bytes per element //mode_ptr *_mode; // SRAM footprint: 4 bytes per element
const char **_modeData; // mode (effect) name and its slider control data array //const char **_modeData; // mode (effect) name and its slider control data array
std::vector<mode_ptr> _mode; // SRAM footprint: 4 bytes per element
std::vector<const char*> _modeData; // mode (effect) name and its slider control data array
//std::vector<ModeData> _modes; // this will require substantial rewrite of code
show_callback _callback = nullptr; show_callback _callback = nullptr;
@ -726,9 +813,6 @@ class WS2812FX { // 96 bytes
estimateCurrentAndLimitBri(void), estimateCurrentAndLimitBri(void),
load_gradient_palette(uint8_t), load_gradient_palette(uint8_t),
handle_palette(void); handle_palette(void);
uint16_t
transitionProgress(uint8_t tNr);
}; };
extern const char JSON_mode_names[]; extern const char JSON_mode_names[];

View File

@ -153,6 +153,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
if (!strip.isMatrix) return; // not a matrix set-up if (!strip.isMatrix) return; // not a matrix set-up
uint8_t _bri_t = strip._bri_t; uint8_t _bri_t = strip._bri_t;
//uint8_t _bri_t = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0);
if (_bri_t < 255) { if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t); byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t); byte g = scale8(G(col), _bri_t);

View File

@ -70,57 +70,157 @@
#endif #endif
///////////////////////////////////////////////////////////////////////////////
// ColorTransition class implementation
///////////////////////////////////////////////////////////////////////////////
void ColorTransition::startTransition(Segment *seg, uint16_t dur) {
// starting a transition has to occur before change
if (!seg->isActive()) return;
briOld = currentBri(seg->getOption(SEG_OPTION_ON) ? seg->opacity : 0);
cctOld = currentBri(seg->cct, true);
for (size_t i=0; i<NUM_COLORS; i++) colorOld[i] = currentColor(i, seg->colors[i]);
transitionDur = dur;
transitionStart = millis();
seg->setOption(SEG_OPTION_TRANSITIONAL, true);
}
uint16_t ColorTransition::progress() { //transition progression between 0-65535
uint32_t timeNow = millis();
if (timeNow - transitionStart > transitionDur) return 0xFFFFU;
uint32_t elapsed = timeNow - transitionStart;
return min(0xFFFFU, elapsed * 0xFFFFU / transitionDur);
}
uint8_t ColorTransition::currentBri(uint8_t briNew, bool useCct) {
uint32_t prog = progress() + 1;
if (useCct) return ((briNew * prog) + cctOld * (0x10000 - prog)) >> 16;
else return ((briNew * prog) + briOld * (0x10000 - prog)) >> 16;
}
void ColorTransition::handleTransition(Segment *seg, uint8_t &newBri, uint8_t &newCct, uint32_t *newCol) {
newBri = currentBri(newBri);
newCct = currentBri(newCct, true);
for (size_t i=0; i<NUM_COLORS; i++) newCol[i] = currentColor(i, newCol[i]);
unsigned long maxWait = millis() + 22;
if (seg->mode == FX_MODE_STATIC && seg->runtime.next_time > maxWait) seg->runtime.next_time = maxWait;
if (progress() == 0xFFFFU && seg->getOption(SEG_OPTION_TRANSITIONAL)) {
// finish transition
briOld = newBri;
cctOld = newCct;
for (size_t i=0; i<NUM_COLORS; i++) colorOld[i] = newCol[i];
seg->setOption(SEG_OPTION_TRANSITIONAL, false);
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Segment class implementation // Segment class implementation
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
Segment::Segment(const Segment &orig) {
DEBUG_PRINTLN(F("-- Segment duplicated --"));
memcpy(this, &orig, sizeof(Segment));
name = nullptr;
data = nullptr;
_dataLen = 0;
//_t = nullptr;
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
if (orig.data) { allocateData(orig._dataLen); memcpy(data, orig.data, orig._dataLen); }
//if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
DEBUG_PRINTF(" Original data: %p (%d)\n", orig.data, (int)orig._dataLen);
DEBUG_PRINTF(" Constructed data: %p (%d)\n", data, (int)_dataLen);
}
Segment::Segment(Segment &&orig) noexcept {
DEBUG_PRINTLN(F("-- Move constructor --"));
memcpy(this, &orig, sizeof(Segment));
orig.name = nullptr;
orig.data = nullptr;
//orig._t = nullptr;
}
Segment& Segment::operator= (const Segment &orig) {
DEBUG_PRINTLN(F("-- Segment copied --"));
if (this != &orig) {
if (name) delete[] name;
//if (_t) delete _t;
deallocateData();
memcpy(this, &orig, sizeof(Segment));
name = nullptr;
data = nullptr;
_dataLen = 0;
//_t = nullptr;
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
if (orig.data) { allocateData(orig._dataLen); memcpy(data, orig.data, orig._dataLen); }
//if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
DEBUG_PRINTF(" Copied data: %p (%d)\n", orig.data, (int)orig._dataLen);
DEBUG_PRINTF(" New data: %p (%d)\n", data, (int)_dataLen);
}
return *this;
}
Segment& Segment::operator= (Segment &&orig) noexcept {
DEBUG_PRINTLN(F("-- Moving segment --"));
if (this != &orig) {
if (name) delete[] name; // free old name
//if (_t) delete _t;
deallocateData(); // free old runtime data
memcpy(this, &orig, sizeof(Segment));
orig.name = nullptr;
orig.data = nullptr;
//orig._t = nullptr;
}
return *this;
}
bool Segment::allocateData(uint16_t len) {
if (data && _dataLen == len) return true; //already allocated
DEBUG_PRINTF("-- Allocating data (size:%d) --\n", len);
deallocateData();
if (strip.getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
// if possible use SPI RAM on ESP32
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
if (psramFound())
data = (byte*) ps_malloc(len);
else
#endif
data = (byte*) malloc(len);
if (!data) return false; //allocation failed
strip.addUsedSegmentData(len);
_dataLen = len;
memset(data, 0, len);
return true;
}
void Segment::deallocateData() {
if (!data) return;
DEBUG_PRINTF("-- Deallocating data: %p (%d) --\n", data, (int)_dataLen);
free(data);
data = nullptr;
strip.addUsedSegmentData(-(int16_t)_dataLen);
_dataLen = 0;
}
/**
* If reset of this segment was requested, clears runtime
* settings of this segment.
* Must not be called while an effect mode function is running
* because it could access the data buffer and this method
* may free that data buffer.
*/
void Segment::resetIfRequired() {
if (reset) { // (getOption(SEG_OPTION_RESET))
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
deallocateData();
reset = false; // setOption(SEG_OPTION_RESET, false);
}
}
void Segment::startTransition(uint16_t dur) {
// starting a transition has to occur before change so we get current values 1st
/*uint8_t*/ _briT = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0); // comment out uint8_t if not using Transition struct
/*uint8_t*/ _cctT = currentBri(cct, true); // comment out uint8_t if not using Transition struct
//uint32_t _colorT[NUM_COLORS]; // comment out if not using Transition struct
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = currentColor(i, colors[i]);
// comment out if not using Transition struct
//if (!_t) _t = new Transition(dur); // no previous transition running
//if (!_t) return; // failed to allocat data
//_t->_briT = _briT;
//_t->_cctT = _cctT;
//for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = _colorT[i];
setOption(SEG_OPTION_TRANSITIONAL, true);
}
uint16_t Segment::progress() { //transition progression between 0-65535
//if (!_t) return 0xFFFFU;
uint32_t timeNow = millis();
if (timeNow - /*_t->*/_start > /*_t->*/_dur) return 0xFFFFU;
return (timeNow - /*_t->*/_start) * 0xFFFFU / /*_t->*/_dur;
}
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
//if (!_t) return (useCct) ? cct : opacity;
if (getOption(SEG_OPTION_TRANSITIONAL)) {
uint32_t prog = progress() + 1;
if (useCct) return ((briNew * prog) + /*_t->*/_cctT * (0x10000 - prog)) >> 16;
else return ((briNew * prog) + /*_t->*/_briT * (0x10000 - prog)) >> 16;
} else {
return (useCct) ? cct : (getOption(SEG_OPTION_ON) ? opacity : 0);
}
}
void Segment::handleTransition() {
if (!getOption(SEG_OPTION_TRANSITIONAL)) return;
unsigned long maxWait = millis() + 20;
if (mode == FX_MODE_STATIC && next_time > maxWait) next_time = maxWait;
if (progress() == 0xFFFFU) {
//if (_t) { delete _t; _t = nullptr; }
setOption(SEG_OPTION_TRANSITIONAL, false); // finish transitioning segment
}
}
bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed
if (slot >= NUM_COLORS || c == colors[slot]) return false; if (slot >= NUM_COLORS || c == colors[slot]) return false;
transition.startTransition(this, strip.getTransition()); // start transition prior to change startTransition(strip.getTransition()); // start transition prior to change
colors[slot] = c; colors[slot] = c;
return true; return true;
} }
@ -132,19 +232,19 @@ void Segment::setCCT(uint16_t k) {
k = (k - 1900) >> 5; k = (k - 1900) >> 5;
} }
if (cct == k) return; if (cct == k) return;
transition.startTransition(this, strip.getTransition()); // start transition prior to change startTransition(strip.getTransition()); // start transition prior to change
cct = k; cct = k;
} }
void Segment::setOpacity(uint8_t o) { void Segment::setOpacity(uint8_t o) {
if (opacity == o) return; if (opacity == o) return;
transition.startTransition(this, strip.getTransition()); // start transition prior to change startTransition(strip.getTransition()); // start transition prior to change
opacity = o; opacity = o;
} }
void Segment::setOption(uint8_t n, bool val) { void Segment::setOption(uint8_t n, bool val) {
bool prevOn = getOption(SEG_OPTION_ON); bool prevOn = getOption(SEG_OPTION_ON);
if (n == SEG_OPTION_ON && val != prevOn) transition.startTransition(this, strip.getTransition()); // start transition prior to change if (n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
if (val) options |= 0x01 << n; if (val) options |= 0x01 << n;
else options &= ~(0x01 << n); else options &= ~(0x01 << n);
} }
@ -185,6 +285,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
uint16_t len = length(); uint16_t len = length();
uint8_t _bri_t = strip._bri_t; uint8_t _bri_t = strip._bri_t;
//uint8_t _bri_t = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0);
if (_bri_t < 255) { if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t); byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t); byte g = scale8(G(col), _bri_t);
@ -289,9 +390,6 @@ uint8_t Segment::differs(Segment& b) {
} }
void Segment::refreshLightCapabilities() { void Segment::refreshLightCapabilities() {
if (!isActive()) {
_capabilities = 0; return;
}
uint8_t capabilities = 0; uint8_t capabilities = 0;
for (uint8_t b = 0; b < busses.getNumBusses(); b++) { for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
@ -487,51 +585,6 @@ uint32_t IRAM_ATTR Segment::color_from_palette(uint16_t i, bool mapping, bool wr
} }
///////////////////////////////////////////////////////////////////////////////
// Segmentruntime class implementation
///////////////////////////////////////////////////////////////////////////////
bool Segmentruntime::allocateData(uint16_t len){
if (data && _dataLen == len) return true; //already allocated
deallocateData();
if (strip.getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
// if possible use SPI RAM on ESP32
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
if (psramFound())
data = (byte*) ps_malloc(len);
else
#endif
data = (byte*) malloc(len);
if (!data) return false; //allocation failed
strip.addUsedSegmentData(len);
_dataLen = len;
memset(data, 0, len);
return true;
}
void Segmentruntime::deallocateData() {
free(data);
data = nullptr;
strip.addUsedSegmentData(-(int16_t)_dataLen);
_dataLen = 0;
}
/**
* If reset of this segment was request, clears runtime
* settings of this segment.
* Must not be called while an effect mode function is running
* because it could access the data buffer and this method
* may free that data buffer.
*/
void Segmentruntime::resetIfRequired() {
if (_requiresReset) {
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
deallocateData();
_requiresReset = false;
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// WS2812FX class implementation // WS2812FX class implementation
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -540,10 +593,14 @@ void Segmentruntime::resetIfRequired() {
void WS2812FX::finalizeInit(void) void WS2812FX::finalizeInit(void)
{ {
//reset segment runtimes //reset segment runtimes
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { for (segment &seg : _segments) {
_segments[i].runtime.markForReset(); seg.markForReset();
_segments[i].runtime.resetIfRequired(); seg.resetIfRequired();
} }
// for (uint8_t i = 0; i < getMaxSegments(); i++) {
// _segments[i].markForReset();
// _segments[i].resetIfRequired();
// }
_hasWhiteChannel = _isOffRefreshRequired = false; _hasWhiteChannel = _isOffRefreshRequired = false;
@ -596,21 +653,18 @@ void WS2812FX::service() {
if (nowUp - _lastShow < MIN_SHOW_DELAY) return; if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
bool doShow = false; bool doShow = false;
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++) _segment_index = 0;
{ for (segment &seg : _segments) {
//if (realtimeMode && useMainSegmentOnly && i == getMainSegmentId()) continue; // for (int i = 0; i < getMaxSegments(); i++) {
// Segment &seg = getSegment(i);
_segment_index = i;
Segment &seg = _segments[_segment_index];
// reset the segment runtime data if needed, called before isActive to ensure deleted // reset the segment runtime data if needed, called before isActive to ensure deleted
// segment's buffers are cleared // segment's buffers are cleared
seg.runtime.resetIfRequired(); seg.resetIfRequired();
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
// last condition ensures all solid segments are updated at the same time // last condition ensures all solid segments are updated at the same time
if(nowUp > seg.runtime.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) if(nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
{ {
if (seg.grouping == 0) seg.grouping = 1; //sanity check if (seg.grouping == 0) seg.grouping = 1; //sanity check
doShow = true; doShow = true;
@ -618,12 +672,12 @@ void WS2812FX::service() {
if (!seg.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen if (!seg.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
_virtualSegmentLength = seg.virtualLength(); _virtualSegmentLength = seg.virtualLength();
_bri_t = seg.getOption(SEG_OPTION_ON) ? seg.opacity : 0; _bri_t = seg.currentBri(seg.getOption(SEG_OPTION_ON) ? seg.opacity : 0);
uint8_t _cct_t = seg.cct; uint8_t _cct_t = seg.currentBri(seg.cct, true);
_colors_t[0] = seg.colors[0]; _colors_t[0] = seg.currentColor(0, seg.colors[0]);
_colors_t[1] = seg.colors[1]; _colors_t[1] = seg.currentColor(1, seg.colors[1]);
_colors_t[2] = seg.colors[2]; _colors_t[2] = seg.currentColor(2, seg.colors[2]);
seg.transition.handleTransition(&seg, _bri_t, _cct_t, _colors_t); seg.handleTransition();
if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB); if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB);
for (uint8_t c = 0; c < NUM_COLORS; c++) { for (uint8_t c = 0; c < NUM_COLORS; c++) {
@ -632,11 +686,12 @@ void WS2812FX::service() {
handle_palette(); handle_palette();
delay = (*_mode[seg.mode])(); delay = (*_mode[seg.mode])();
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.runtime.call++; if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
} }
seg.runtime.next_time = nowUp + delay; seg.next_time = nowUp + delay;
} }
_segment_index++;
} }
_virtualSegmentLength = 0; _virtualSegmentLength = 0;
busses.setSegmentCCT(-1); busses.setSegmentCCT(-1);
@ -838,13 +893,14 @@ void WS2812FX::setTargetFps(uint8_t fps) {
} }
void WS2812FX::setMode(uint8_t segid, uint8_t m) { void WS2812FX::setMode(uint8_t segid, uint8_t m) {
if (segid >= MAX_NUM_SEGMENTS) return; if (segid >= _segments.size()) return;
// if (segid >= getMaxSegments()) return;
if (m >= getModeCount()) m = getModeCount() - 1; if (m >= getModeCount()) m = getModeCount() - 1;
if (_segments[segid].mode != m) if (_segments[segid].mode != m) {
{ //_segments[segid].startTransition(strip.getTransition()); // set effect transitions
_segments[segid].runtime.markForReset(); _segments[segid].markForReset();
_segments[segid].mode = m; _segments[segid].mode = m;
} }
} }
@ -853,19 +909,21 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) {
void WS2812FX::setColor(uint8_t slot, uint32_t c) { void WS2812FX::setColor(uint8_t slot, uint32_t c) {
if (slot >= NUM_COLORS) return; if (slot >= NUM_COLORS) return;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) for (segment &seg : _segments) {
{ // for (int i = 0; i < getMaxSegments(); i++) {
if (_segments[i].isActive() && _segments[i].isSelected()) { // Segment &seg = getSegment(i);
_segments[i].setColor(slot, c); if (seg.isSelected()) {
seg.setColor(slot, c);
} }
} }
} }
void WS2812FX::setCCT(uint16_t k) { void WS2812FX::setCCT(uint16_t k) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) for (segment &seg : _segments) {
{ // for (int i = 0; i < getMaxSegments(); i++) {
if (_segments[i].isActive() && _segments[i].isSelected()) { // Segment &seg = getSegment(i);
_segments[i].setCCT(k); if (seg.isActive() && seg.isSelected()) {
seg.setCCT(k);
} }
} }
} }
@ -875,9 +933,10 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
if (_brightness == b) return; if (_brightness == b) return;
_brightness = b; _brightness = b;
if (_brightness == 0) { //unfreeze all segments on power off if (_brightness == 0) { //unfreeze all segments on power off
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) for (segment &seg : _segments) {
{ // for (int i = 0; i < getMaxSegments(); i++) {
_segments[i].setOption(SEG_OPTION_FREEZE, false); // Segment &seg = getSegment(i);
seg.setOption(SEG_OPTION_FREEZE, false);
} }
} }
if (direct) { if (direct) {
@ -885,51 +944,56 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
busses.setBrightness(b); busses.setBrightness(b);
} else { } else {
unsigned long t = millis(); unsigned long t = millis();
if (_segments[0].runtime.next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
} }
} }
uint8_t WS2812FX::getFirstSelectedSegId(void) uint8_t WS2812FX::getFirstSelectedSegId(void)
{ {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) size_t i = 0;
{ for (segment &seg : _segments) {
if (_segments[i].isActive() && _segments[i].isSelected()) return i; // for (int i = 0; i < getMaxSegments(); i++) {
// Segment &seg = getSegment(i);
if (seg.isSelected()) return i;
i++;
} }
// if none selected, use the main segment // if none selected, use the main segment
return getMainSegmentId(); return getMainSegmentId();
} }
void WS2812FX::setMainSegmentId(uint8_t n) { void WS2812FX::setMainSegmentId(uint8_t n) {
if (n >= MAX_NUM_SEGMENTS) return; // if (n >= getMaxSegments()) return;
//use supplied n if active, or first active // //use supplied n if active, or first active
if (_segments[n].isActive()) { // if (_segments[n].isActive()) {
_mainSegment = n; return; // _mainSegment = n; return;
} // }
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) // for (uint8_t i = 0; i < getMaxSegments(); i++) {
{ // if (_segments[i].isActive()) {
if (_segments[i].isActive()) { // _mainSegment = i; return;
_mainSegment = i; return; // }
} // }
}
_mainSegment = 0; _mainSegment = 0;
if (n < _segments.size()) {
_mainSegment = n;
}
return; return;
} }
uint8_t WS2812FX::getLastActiveSegmentId(void) { uint8_t WS2812FX::getLastActiveSegmentId(void) {
for (uint8_t i = MAX_NUM_SEGMENTS -1; i > 0; i--) { // for (uint8_t i = getMaxSegments() -1; i > 0; i--) {
if (_segments[i].isActive()) return i; // if (_segments[i].isActive()) return i;
} // }
return 0; // return 0;
return _segments.size()-1;
} }
uint8_t WS2812FX::getActiveSegmentsNum(void) { //uint8_t WS2812FX::getActiveSegmentsNum(void) {
uint8_t c = 0; // uint8_t c = 0;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) // for (uint8_t i = 0; i < getMaxSegments(); i++) {
{ // if (_segments[i].isActive()) c++;
if (_segments[i].isActive()) c++; // }
} // return c;
return c; //}
}
uint16_t WS2812FX::getLengthPhysical(void) { uint16_t WS2812FX::getLengthPhysical(void) {
uint16_t len = 0; uint16_t len = 0;
@ -972,8 +1036,21 @@ bool WS2812FX::hasCCTBus(void) {
return false; return false;
} }
void WS2812FX::purgeSegments(void) {
// remove inactive segments at the back
//while (_segments.back().stop == 0 && _segments.size() > 1) _segments.pop_back();
// remove all inactive segments (from the back)
int deleted = 0;
for (int i = _segments.size()-1; i > 0; i--) if (_segments[i].stop == 0) { DEBUG_PRINT(F(" Removing segment: ")); DEBUG_PRINTLN(i); deleted++; _segments.erase(_segments.begin() + i); }
if (deleted) {
_segments.shrink_to_fit();
if (_mainSegment >= _segments.size()) setMainSegmentId(0);
}
}
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) { void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
if (n >= MAX_NUM_SEGMENTS) return; if (n >= _segments.size()) return;
// if (n >= getMaxSegments()) return;
Segment& seg = _segments[n]; Segment& seg = _segments[n];
//return if neither bounds nor grouping have changed //return if neither bounds nor grouping have changed
@ -985,9 +1062,12 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
&& (!grouping || (seg.grouping == grouping && seg.spacing == spacing)) && (!grouping || (seg.grouping == grouping && seg.spacing == spacing))
&& (offset == UINT16_MAX || offset == seg.offset)) return; && (offset == UINT16_MAX || offset == seg.offset)) return;
if (seg.stop) setRange(seg.start, seg.stop -1, 0); //turn old segment range off //if (seg.stop) setRange(seg.start, seg.stop -1, BLACK); //turn old segment range off
if (seg.stop) seg.fill(BLACK); //turn old segment range off
if (i2 <= i1) //disable segment if (i2 <= i1) //disable segment
{ {
// disabled segments should get removed using purgeSegments()
DEBUG_PRINTLN(F(" Segment marked inactive."));
seg.stop = 0; seg.stop = 0;
if (seg.name) { if (seg.name) {
delete[] seg.name; delete[] seg.name;
@ -995,6 +1075,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
} }
// if main segment is deleted, set first active as main segment // if main segment is deleted, set first active as main segment
if (n == _mainSegment) setMainSegmentId(0); if (n == _mainSegment) setMainSegmentId(0);
seg.markForReset();
return; return;
} }
if (isMatrix) { if (isMatrix) {
@ -1015,18 +1096,25 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
seg.spacing = spacing; seg.spacing = spacing;
} }
if (offset < UINT16_MAX) seg.offset = offset; if (offset < UINT16_MAX) seg.offset = offset;
_segments[n].runtime.markForReset(); seg.markForReset();
if (!boundsUnchanged) seg.refreshLightCapabilities(); if (!boundsUnchanged) seg.refreshLightCapabilities();
} }
void WS2812FX::restartRuntime() { void WS2812FX::restartRuntime() {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { for (segment &seg : _segments) seg.markForReset();
_segments[i].runtime.markForReset(); // for (uint8_t i = 0; i < getMaxSegments(); i++) {
} // Segment &seg = getSegment(i);
// seg.markForReset();
// }
} }
void WS2812FX::resetSegments() { void WS2812FX::resetSegments() {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete[] _segments[i].name; _segments.clear(); // destructs all Segment as part of clearing
segment seg = isMatrix ? Segment(0, matrixWidth, 0, matrixHeight) : Segment(0, _length);
_segments.push_back(seg);
_mainSegment = 0;
/*
for (uint8_t i = 0; i < getMaxSegments(); i++) if (_segments[i].name) delete[] _segments[i].name;
_mainSegment = 0; _mainSegment = 0;
memset(_segments, 0, sizeof(_segments)); memset(_segments, 0, sizeof(_segments));
//memset(_segmentruntimes, 0, sizeof(_segmentruntimes)); //memset(_segmentruntimes, 0, sizeof(_segmentruntimes));
@ -1034,9 +1122,11 @@ void WS2812FX::resetSegments() {
_segments[0].mode = DEFAULT_MODE; _segments[0].mode = DEFAULT_MODE;
_segments[0].colors[0] = DEFAULT_COLOR; _segments[0].colors[0] = DEFAULT_COLOR;
_segments[0].start = 0; _segments[0].start = 0;
_segments[0].startY = 0;
_segments[0].speed = DEFAULT_SPEED; _segments[0].speed = DEFAULT_SPEED;
_segments[0].intensity = DEFAULT_INTENSITY; _segments[0].intensity = DEFAULT_INTENSITY;
_segments[0].stop = _length; _segments[0].stop = isMatrix ? matrixWidth : _length;
_segments[0].stopY = isMatrix ? matrixHeight : 1;
_segments[0].grouping = 1; _segments[0].grouping = 1;
_segments[0].setOption(SEG_OPTION_SELECTED, 1); _segments[0].setOption(SEG_OPTION_SELECTED, 1);
_segments[0].setOption(SEG_OPTION_ON, 1); _segments[0].setOption(SEG_OPTION_ON, 1);
@ -1046,7 +1136,7 @@ void WS2812FX::resetSegments() {
_segments[0].custom2 = DEFAULT_C2; _segments[0].custom2 = DEFAULT_C2;
_segments[0].custom3 = DEFAULT_C3; _segments[0].custom3 = DEFAULT_C3;
for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++) for (uint16_t i = 1; i < getMaxSegments(); i++)
{ {
_segments[i].colors[0] = _segments[i].color_wheel(i*51); _segments[i].colors[0] = _segments[i].color_wheel(i*51);
_segments[i].grouping = 1; _segments[i].grouping = 1;
@ -1058,23 +1148,25 @@ void WS2812FX::resetSegments() {
_segments[i].custom1 = DEFAULT_C1; _segments[i].custom1 = DEFAULT_C1;
_segments[i].custom2 = DEFAULT_C2; _segments[i].custom2 = DEFAULT_C2;
_segments[i].custom3 = DEFAULT_C3; _segments[i].custom3 = DEFAULT_C3;
_segments[i].runtime.markForReset(); _segments[i].markForReset();
} }
_segments[0].runtime.markForReset(); _segments[0].markForReset();
*/
} }
void WS2812FX::makeAutoSegments(bool forceReset) { void WS2812FX::makeAutoSegments(bool forceReset) {
if (isMatrix) { if (isMatrix) {
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
// only create 1 2D segment // only create 1 2D segment
uint8_t mainSeg = getMainSegmentId(); if (forceReset || getActiveSegmentsNum() == 0) resetSegments(); // initialises 1 segment
if (forceReset) { else if (getActiveSegmentsNum() == 1) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { _segments[0].start = 0;
setSegment(i, 0, 0); _segments[0].stop = matrixWidth;
} _segments[0].startY = 0;
} _segments[0].stopY = matrixHeight;
if (getActiveSegmentsNum() < 2) { _segments[0].grouping = 1;
setSegment(mainSeg, 0, matrixWidth, 1, 0, 0, 0, matrixHeight); _segments[0].spacing = 0;
_mainSegment = 0;
} }
#endif #endif
} else if (autoSegments) { //make one segment per bus } else if (autoSegments) { //make one segment per bus
@ -1098,22 +1190,24 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
} }
s++; s++;
} }
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { _segments.clear();
_segments[i].setOption(SEG_OPTION_SELECTED, true); for (uint8_t i = 0; i < s; i++) {
setSegment(i, segStarts[i], segStops[i]); Segment seg = Segment(segStarts[i], segStops[i]);
seg.setOption(SEG_OPTION_SELECTED, true);
_segments.push_back(seg);
} }
// for (uint8_t i = 0; i < getMaxSegments(); i++) {
// _segments[i].setOption(SEG_OPTION_SELECTED, true);
// setSegment(i, segStarts[i], segStops[i]);
// }
_mainSegment = 0;
} else { } else {
if (forceReset || getActiveSegmentsNum() == 0) resetSegments();
//expand the main seg to the entire length, but only if there are no other segments, or reset is forced //expand the main seg to the entire length, but only if there are no other segments, or reset is forced
uint8_t mainSeg = getMainSegmentId(); else if (getActiveSegmentsNum() == 1) {
_segments[0].start = 0;
if (forceReset) { _segments[0].stop = _length;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { _mainSegment = 0;
setSegment(i, 0, 0);
}
}
if (getActiveSegmentsNum() < 2) {
setSegment(mainSeg, 0, _length);
} }
} }
@ -1122,26 +1216,32 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
void WS2812FX::fixInvalidSegments() { void WS2812FX::fixInvalidSegments() {
//make sure no segment is longer than total (sanity check) //make sure no segment is longer than total (sanity check)
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) size_t i = 0;
{ for (std::vector<Segment>::iterator it = _segments.begin(); it != _segments.end(); i++, it++) {
if (_segments[i].start >= _length) setSegment(i, 0, 0); if (_segments[i].start >= _length) { _segments.erase(it); i--; it--; continue; }
if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length); if (_segments[i].stop > _length) _segments[i].stop = _length;
// this is always called as the last step after finalizeInit(), update covered bus types // this is always called as the last step after finalizeInit(), update covered bus types
getSegment(i).refreshLightCapabilities(); _segments[i].refreshLightCapabilities();
} }
// for (uint8_t i = 0; i < getMaxSegments(); i++) {
// if (_segments[i].start >= _length) { _segments[i].start = _segments[i].stop = 0; _segments[i].markForReset(); }
// if (_segments[i].stop > _length) { _segments[i].stop = _length; _segments[i].markForReset(); }
// // this is always called as the last step after finalizeInit(), update covered bus types
// if (_segments[i].isActive()) _segments[i].refreshLightCapabilities();
// }
} }
//true if all segments align with a bus, or if a segment covers the total length //true if all segments align with a bus, or if a segment covers the total length
bool WS2812FX::checkSegmentAlignment() { bool WS2812FX::checkSegmentAlignment() {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].start >= _segments[i].stop) continue; //inactive segment
bool aligned = false; bool aligned = false;
for (segment &seg : _segments) {
// for (uint8_t i = 0; i < getMaxSegments(); i++) {
// Segment &seg = getSegment(i);
for (uint8_t b = 0; b<busses.getNumBusses(); b++) { for (uint8_t b = 0; b<busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b); Bus *bus = busses.getBus(b);
if (_segments[i].start == bus->getStart() && _segments[i].stop == bus->getStart() + bus->getLength()) aligned = true; if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
} }
if (_segments[i].start == 0 && _segments[i].stop == _length) aligned = true; if (seg.start == 0 && seg.stop == _length) aligned = true;
if (!aligned) return false; if (!aligned) return false;
} }
return true; return true;
@ -1153,7 +1253,8 @@ bool WS2812FX::checkSegmentAlignment() {
uint8_t WS2812FX::setPixelSegment(uint8_t n) uint8_t WS2812FX::setPixelSegment(uint8_t n)
{ {
uint8_t prevSegId = _segment_index; uint8_t prevSegId = _segment_index;
if (n < MAX_NUM_SEGMENTS) { if (n < _segments.size()) {
// if (n < getMaxSegments()) {
_segment_index = n; _segment_index = n;
_virtualSegmentLength = _segments[_segment_index].virtualLength(); _virtualSegmentLength = _segments[_segment_index].virtualLength();
} }
@ -1173,20 +1274,11 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
void WS2812FX::setTransitionMode(bool t) void WS2812FX::setTransitionMode(bool t)
{ {
unsigned long waitMax = millis() + 22; //refresh after 20 ms if transition enabled for (segment &seg : _segments) seg.startTransition(t ? getTransition() : 0);
for (uint16_t i = 0; i < MAX_NUM_SEGMENTS; i++) // for (uint8_t i = 0; i < getMaxSegments(); i++) {
{ // Segment &seg = getSegment(i);
if (_segments[i].isActive() && !_segments[i].getOption(SEG_OPTION_TRANSITIONAL)) { // seg.startTransition(t ? getTransition() : 0);
if (t) { // }
_segments[i].transition.transitionStart = millis();
_segments[i].transition.transitionDur = strip.getTransition();
}
_segments[i].setOption(SEG_OPTION_TRANSITIONAL, t);
if (t && _segments[i].mode == FX_MODE_STATIC && _segments[i].runtime.next_time > waitMax) {
_segments[i].runtime.next_time = waitMax;
}
}
}
} }
void WS2812FX::load_gradient_palette(uint8_t index) void WS2812FX::load_gradient_palette(uint8_t index)
@ -1313,7 +1405,7 @@ void WS2812FX::handle_palette(void)
load_gradient_palette(paletteIndex -13); load_gradient_palette(paletteIndex -13);
} }
if (singleSegmentMode && paletteFade && _segments[_segment_index].runtime.call > 0) //only blend if just one segment uses FastLED mode if (singleSegmentMode && paletteFade && _segments[_segment_index].call > 0) //only blend if just one segment uses FastLED mode
{ {
nblendPaletteTowardPalette(currentPalette, targetPalette, 48); nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
} else } else
@ -1428,180 +1520,7 @@ 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;
// WLEDSR: extensions
// Technical notes
// ===============
// If an effect name is followed by an @, slider and color control is effective.
// See setSliderAndColorControl in index.js for implementation
// If not effective then:
// - For AC effects (id<128) 2 sliders and 3 colors and the palette will be shown
// - For SR effects (id>128) 5 sliders and 3 colors and the palette will be shown
// If effective (@)
// - a ; seperates slider controls (left) from color controls (middle) and palette control (right)
// - if left, middle or right is empty no controls are shown
// - a , seperates slider controls (max 5) or color controls (max 3). Palette has only one value
// - a ! means that the default is used.
// - For sliders: Effect speeds, Effect intensity, Custom 1, Custom 2, Custom 3
// - For colors: Fx color, Background color, Custom
// - For palette: prompt for color palette OR palette ID if numeric (will hide palette selection)
//
// Note: If palette is on and no colors are specified 1,2 and 3 is shown in each color circle.
// If a color is specified, the 1,2 or 3 is replaced by that specification.
// Note: Effects can override default pattern behaviour
// - FadeToBlack can override the background setting
// - Defining SEGCOL(<i>) can override a specific palette using these values (e.g. Color Gradient)
const char JSON_mode_names[] PROGMEM = R"=====(["Mode names have moved"])====="; const char JSON_mode_names[] PROGMEM = R"=====(["Mode names have moved"])=====";
/*
R"=====([
"Solid",
"Blink@!,;!,!,;!",
"Breathe@!,;!,!;!",
"Wipe@!,!;!,!,;!",
"Wipe Random@!,;1,2,3;!",
"Random Colors@!,Fade time;1,2,3;!",
"Sweep@!,!;!,!,;!",
"Dynamic@!,!;1,2,3;!",
"Colorloop@!,Saturation;1,2,3;!",
"Rainbow@!,Size;1,2,3;!",
"Scan@!,# of dots;!,!,;!",
"Scan Dual@!,# of dots;!,!,;!",
"Fade@!,;!,!,;!",
"Theater@!,Gap size;!,!,;!",
"Theater Rainbow@!,Gap size;1,2,3;!",
"Running@!,Wave width;!,!,;!",
"Saw@!,Width;!,!,;!",
"Twinkle@!,;!,!,;!",
"Dissolve@Repeat speed,Dissolve speed;!,!,;!",
"Dissolve Rnd@Repeat speed,Dissolve speed;,!,;!",
"Sparkle@!,;!,!,;!",
"Sparkle Dark@!,!;Bg,Fx,;!",
"Sparkle+@!,!;Bg,Fx,;!",
"Strobe@!,;!,!,;!",
"Strobe Rainbow@!,;,!,;!",
"Strobe Mega@!,!;!,!,;!",
"Blink Rainbow@Frequency,Blink duration;!,!,;!",
"Android@!,Width;!,!,;!",
"Chase@!,Width;!,!,!;!",
"Chase Random@!,Width;!,,!;!",
"Chase Rainbow@!,Width;!,!,;0",
"Chase Flash@!,;Bg,Fx,!;!",
"Chase Flash Rnd@!,;,Fx,;!",
"Rainbow Runner@!,Size;Bg,,;!",
"Colorful@!,Saturation;1,2,3;!",
"Traffic Light@!,;,!,;!",
"Sweep Random",
"Chase 2@!,Width;!,!,;!",
"Aurora@!=24,!;1,2,3;!=50",
"Stream",
"Scanner",
"Lighthouse",
"Fireworks@Sharpness=96,Frequency=192;!,2,;!=11",
"Rain@Fade rate=128,Frequency=128;!,2,;!",
"Tetrix@!=224,Width=0;!,!,;!=11",
"Fire Flicker@!,!;!,,;!",
"Gradient@!,Spread=16;!,!,;!",
"Loading@!,Fade=16;!,!,;!",
"Police@!,Width;,Bg,;0",
"Fairy",
"Two Dots@!,Dot size;1,2,Bg;!",
"Fairy Twinkle",
"Running Dual",
"Halloween",
"Chase 3@!,Size;1,2,3;0",
"Tri Wipe@!,Width;1,2,3;0",
"Tri Fade",
"Lightning",
"ICU",
"Multi Comet",
"Scanner Dual",
"Stream 2",
"Oscillate",
"Pride 2015@!,;;",
"Juggle@!=16,Trail=240;!,!,;!",
"Palette@!,;1,2,3;!",
"Fire 2012@Spark rate=120,Decay=64;1,2,3;!",
"Colorwaves",
"Bpm@!=64,;1,2,3;!",
"Fill Noise",
"Noise 1",
"Noise 2",
"Noise 3",
"Noise 4",
"Colortwinkles@Fade speed,Spawn speed;1,2,3;!",
"Lake@!,;1,2,3;!",
"Meteor@!,Trail length;!,!,;!",
"Meteor Smooth@!,Trail length;!,!,;!",
"Railway",
"Ripple",
"Twinklefox",
"Twinklecat",
"Halloween Eyes@Duration,Eye fade time;Fx,Bg,;!",
"Solid Pattern@Fg size,Bg size;Fg,Bg,;!=0",
"Solid Pattern Tri@,Size;1,2,3;!=0",
"Spots@Spread,Width;!,!,;!",
"Spots Fade@Spread,Width;!,!,;!",
"Glitter",
"Candle@Flicker rate=96,Flicker intensity=224;!,!,;0",
"Fireworks Starburst",
"Fireworks 1D@Gravity,Firing side;!,!,;!",
"Bouncing Balls@Gravity,# of balls;!,!,;!",
"Sinelon",
"Sinelon Dual",
"Sinelon Rainbow",
"Popcorn",
"Drip@Gravity,# of drips;!,!;!",
"Plasma@Phase,;1,2,3;!",
"Percent@,% of fill;!,!,;!",
"Ripple Rainbow",
"Heartbeat@!,!;!,!,;!",
"Pacifica",
"Candle Multi@Flicker rate=96,Flicker intensity=224;!,!,;0",
"Solid Glitter@,!;!,,;0",
"Sunrise@Time [min]=60,;;0",
"Phased",
"Twinkleup@!,Intensity;!,!,;!",
"Noise Pal",
"Sine",
"Phased Noise",
"Flow",
"Chunchun@!,Gap size;!,!,;!",
"Dancing Shadows@!,# of shadows;!,,;!",
"Washing Machine",
"Candy Cane@!,Width;;",
"Blends@Shift speed,Blend speed;1,2,3,!",
"TV Simulator",
"Dynamic Smooth",
"2D Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.;;",
"2D DNA@Scroll speed,Blur;;!",
"2D DNA Spiral@Scroll speed,Blur;;!",
"2D Drift@Rotation speed,Blur amount;;!",
"2D Firenoise@X scale,Y scale;;",
"2D Frizzles@X frequency,Y frequency;;!",
"2D Hipnotic@X scale,Y scale;;!",
"2D Lissajous@X frequency,Fadetime;!,!,!;!",
"2D Matrix@Falling speed,Spawning rate,Trail,Custom color;Spawn,Trail;",
"2D Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette",
"2D Colored Bursts@Speed,Number of lines;;!",
"2D Game Of Life@!,;!,!;!",
"2D Julia@,Max iterations per pixel,X center,Y center,Area size;;!",
"2D Metaballs@Speed;!,!,!;!",
"2D Noise@Speed,Scale;!,!,!;!",
"2D Plasma Ball@Speed;!,!,!;!",
"2D Polar Lights@Speed,X scale,Palette;!,!,!;!",
"2D Pulser@Speed,Blur;;!",
"2D Sindots@Speed,Dot distance;;!",
"2D Squared Swirl@,,,,Blur;,,;!",
"2D Sun Radiation@Variance,Brightness;;",
"2D Tartan@X scale,Y scale;;!",
"2D Waverly@Fade rate,Sensitivity;;!",
"2D Spaceships@Fade rate,Blur;!,!,!;!",
"2D Crazy Bees@Fade rate,Blur;;",
"2D Ghost Rider@Fade rate,Blur;!,!,!;!",
"2D Blobs@!,# blobs;!,!,!;!"
])=====";
*/
const char JSON_palette_names[] PROGMEM = R"=====([ const char JSON_palette_names[] PROGMEM = R"=====([
"Default","* Random Cycle","* Color 1","* Colors 1&2","* Color Gradient","* Colors Only","Party","Cloud","Lava","Ocean", "Default","* Random Cycle","* Color 1","* Colors 1&2","* Color Gradient","* Colors Only","Party","Cloud","Lava","Ocean",
"Forest","Rainbow","Rainbow Bands","Sunset","Rivendell","Breeze","Red & Blue","Yellowout","Analogous","Splash", "Forest","Rainbow","Rainbow Bands","Sunset","Rivendell","Breeze","Red & Blue","Yellowout","Analogous","Splash",

View File

@ -225,6 +225,7 @@
#define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment #define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment
#define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor #define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed #define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
#define SEG_OPTION_RESET 6 //Segment runtime requires reset
#define SEG_OPTION_TRANSITIONAL 7 #define SEG_OPTION_TRANSITIONAL 7
#define SEG_OPTION_REVERSED_Y 8 #define SEG_OPTION_REVERSED_Y 8
#define SEG_OPTION_MIRROR_Y 9 #define SEG_OPTION_MIRROR_Y 9

View File

@ -2363,6 +2363,11 @@ function rSegs()
bt.style.color = "var(--c-f)"; bt.style.color = "var(--c-f)";
bt.innerHTML = "Reset segments"; bt.innerHTML = "Reset segments";
var obj = {"seg":[{"start":0,"stop":ledCount,"sel":true}]}; var obj = {"seg":[{"start":0,"stop":ledCount,"sel":true}]};
if (isM) {
obj.seg[0].stop = mw;
obj.seg[0].startX = 0;
obj.seg[0].stopY = mh;
}
for (let i=1; i<=lSeg; i++) obj.seg.push({"stop":0}); for (let i=1; i<=lSeg; i++) obj.seg.push({"stop":0});
requestJson(obj); requestJson(obj);
} }

View File

@ -6,9 +6,38 @@
<title>WLED Settings</title> <title>WLED Settings</title>
<script> <script>
var d=document; var d=document;
var loc = false, locip;
function gId(n){return d.getElementById(n);} function gId(n){return d.getElementById(n);}
function S(){GetV();} // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
function GetV(){} function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
GetV();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
}
function S(){
if (window.location.protocol == "file:") {
loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
}
}
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=0';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
}
</script> </script>
<style> <style>
body { body {

View File

@ -41,8 +41,6 @@
} }
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10'; var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
//if (loc) loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
//else { GetV(); UI(); }
} }
var maxPanels=64; var maxPanels=64;
@ -104,9 +102,6 @@ Serpentine: <input type="checkbox" name="P${i}S"></div>`;
gId("pnl_add").style.display = (i<maxPanels) ? "inline":"none"; gId("pnl_add").style.display = (i<maxPanels) ? "inline":"none";
gId("pnl_rem").style.display = (i>1) ? "inline":"none"; gId("pnl_rem").style.display = (i>1) ? "inline":"none";
} }
//values injected by server while sending HTML
//fun-ction GetV() {}
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>

View File

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

View File

@ -8,10 +8,29 @@
<script> <script>
var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32 var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
var customStarts=false,startsDirty=[],maxCOOverrides=5; var customStarts=false,startsDirty=[],maxCOOverrides=5;
var loc = false, locip;
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");} function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
function B(){window.open("/settings","_self");} function B(){window.open("/settings","_self");}
function gId(n){return d.getElementById(n);} function gId(n){return d.getElementById(n);}
function off(n){d.getElementsByName(n)[0].value = -1;} function off(n){d.getElementsByName(n)[0].value = -1;}
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
GetV();checkSi();setABL();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
}
var timeout; var timeout;
function showToast(text, error = false) function showToast(text, error = false)
{ {
@ -506,12 +525,17 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
} }
} }
} }
function S(){GetV();checkSi();setABL();} function S(){
function GetV() if (window.location.protocol == "file:") {
{ loc = true;
//values injected by server while sending HTML locip = localStorage.getItem('locIp');
//d.um_p=[6,7,8,9,10,11,1];bLimits(3,4096,4000,1664);d.Sf.MS.checked=1;addLEDs(1);d.Sf.L00.value=2;d.Sf.LC0.value=30;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=15;d.Sf.CV0.checked=1;d.Sf.SL0.checked=0;addLEDs(1);d.Sf.L01.value=10;d.Sf.L11.value=10;d.Sf.L21.value=1;d.Sf.L31.value=10;d.Sf.LC1.value=60;d.Sf.LT1.value=80;d.Sf.CO1.value=1;d.Sf.LS1.value=0;d.Sf.CV1.checked=0;d.Sf.SL1.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=56;d.Sf.AW.value=3;d.Sf.BO.checked=1;d.Sf.BP.value=80;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=0;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=1;addBtn(0,0,0);addBtn(1,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=0; if (!locip) {
//d.um_p=[6,7,8,9,10,11,14,15,13,1,21,19,22,25,26,27,5,23,18,17];bLimits(10,2048,64000,8192);d.Sf.MS.checked=1;d.Sf.CCT.checked=0;addLEDs(1);d.Sf.L00.value=192;d.Sf.L10.value=168;d.Sf.L20.value=0;d.Sf.L30.value=61;d.Sf.LC0.value=421;d.Sf.LT0.value=80;d.Sf.CO0.value=1;d.Sf.LS0.value=0;d.Sf.CV0.checked=0;d.Sf.SL0.checked=0;d.Sf.RF0.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=127;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=0;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=1;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=-1;d.Sf.RM.checked=1;addBtn(0,-1,0);addBtn(1,-1,0);addBtn(2,-1,0);addBtn(3,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=8; locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
}
}
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=2';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
} }
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>

View File

@ -7,11 +7,30 @@
<title>Misc Settings</title> <title>Misc Settings</title>
<script> <script>
var d = document; var d = document;
var loc = false, locip;
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); } function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
function B() { window.open("/settings","_self"); } function B() { window.open("/settings","_self"); }
function U() { window.open("/update","_self"); } function U() { window.open("/update","_self"); }
function gId(s) { return d.getElementById(s); } function gId(s) { return d.getElementById(s); }
function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); } function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); }
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
GetV();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
}
var timeout; var timeout;
function showToast(text, error = false) function showToast(text, error = false)
{ {
@ -40,16 +59,24 @@
event.preventDefault(); event.preventDefault();
return false; return false;
} }
function GetV() function S() {
{ if (window.location.protocol == "file:") {
//values injected by server while sending HTML loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
}
}
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=6';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
} }
</script> </script>
<style> <style>
@import url("style.css"); @import url("style.css");
</style> </style>
</head> </head>
<body onload="GetV()"> <body onload="S()">
<form id="form_s" name="Sf" method="post"> <form id="form_s" name="Sf" method="post">
<div class="toprow"> <div class="toprow">
<div class="helpB"><button type="button" onclick="H()">?</button></div> <div class="helpB"><button type="button" onclick="H()">?</button></div>

View File

@ -5,25 +5,44 @@
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Sync Settings</title> <title>Sync Settings</title>
<script>var d=document; <script>var d=document;
function gId(s) var loc = false, locip;
{ function gId(s)
{
return d.getElementById(s); return d.getElementById(s);
} }
function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");} function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
function B(){window.open("/settings","_self");} function B(){window.open("/settings","_self");}
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;} function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} } else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
function FC() // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
{ function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
GetV();SetVal();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
}
function FC()
{
for(j=0;j<8;j++) for(j=0;j<8;j++)
{ {
gId("G"+(j+1)).checked=gId("GS").value>>j&1; gId("G"+(j+1)).checked=gId("GS").value>>j&1;
gId("R"+(j+1)).checked=gId("GR").value>>j&1; gId("R"+(j+1)).checked=gId("GR").value>>j&1;
} }
} }
function GC() function GC()
{ {
var a=0, b=0; var a=0, b=0;
var m=1; var m=1;
@ -35,12 +54,22 @@ function GC()
} }
gId("GS").value=a; gId("GS").value=a;
gId("GR").value=b; gId("GR").value=b;
} }
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;} function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();} function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();}
function S(){GetV();SetVal();} function S(){
function GetV(){var d=document;} if (window.location.protocol == "file:") {
</script> loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
}
}
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=4';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
}
</script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>
<body onload="S()"> <body onload="S()">

View File

@ -7,26 +7,42 @@
<title>Time Settings</title> <title>Time Settings</title>
<script> <script>
var d=document; var d=document;
var loc = false, locip;
var el=false; var el=false;
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
function H() function H() { window.open("https://kno.wled.ge/features/settings/#time-settings"); }
{ function B() { window.open("/settings","_self"); }
window.open("https://kno.wled.ge/features/settings/#time-settings"); function gId(s) { return d.getElementById(s); }
} function gN(s) { return d.getElementsByName(s)[0]; }
function B() // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
{ function loadJS(FILE_URL, async = true) {
window.open("/settings","_self"); let scE = d.createElement("script");
} scE.setAttribute("src", FILE_URL);
function S() scE.setAttribute("type", "text/javascript");
{ scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
BTa();GetV();updLoc();Cs();FC(); BTa();GetV();updLoc();Cs();FC();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
} }
function gId(s) function S() {
{ if (window.location.protocol == "file:") {
return d.getElementById(s); loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
} }
function gN(s) { }
return d.getElementsByName(s)[0]; var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=5';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
} }
function expand(o,i) function expand(o,i)
{ {
@ -34,10 +50,7 @@
t.style.display = t.style.display!=="none" ? "none" : ""; t.style.display = t.style.display!=="none" ? "none" : "";
o.innerHTML = t.style.display==="none" ? "&#128197;" : "&#x2715;"; o.innerHTML = t.style.display==="none" ? "&#128197;" : "&#x2715;";
} }
function Cs() function Cs() { gId("cac").style.display=(gN("OL").checked)?"block":"none"; }
{
gId("cac").style.display=(gN("OL").checked)?"block":"none";
}
function BTa() function BTa()
{ {
var ih="<thead><tr><th>En.</th><th>Hour</th><th>Minute</th><th>Preset</th><th></th></tr></thead>"; var ih="<thead><tr><th>En.</th><th>Hour</th><th>Minute</th><th>Preset</th><th></th></tr></thead>";
@ -132,10 +145,6 @@
if (parseFloat(d.Sf.LT.value)<0) { d.Sf.LTR.value = "S"; d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); } else d.Sf.LTR.value = "N"; if (parseFloat(d.Sf.LT.value)<0) { d.Sf.LTR.value = "S"; d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); } else d.Sf.LTR.value = "N";
if (parseFloat(d.Sf.LN.value)<0) { d.Sf.LNR.value = "W"; d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); } else d.Sf.LNR.value = "E"; if (parseFloat(d.Sf.LN.value)<0) { d.Sf.LNR.value = "W"; d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); } else d.Sf.LNR.value = "E";
} }
function GetV()
{
//values injected by server while sending HTML
}
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>

View File

@ -7,6 +7,7 @@
<title>UI Settings</title> <title>UI Settings</title>
<script> <script>
var d = document; var d = document;
var loc = false, locip;
var initial_ds, initial_st, initial_su; var initial_ds, initial_st, initial_su;
var sett = null; var sett = null;
var l = { var l = {
@ -41,10 +42,7 @@
} }
} }
}; };
function gId(s) function gId(s) { return d.getElementById(s); }
{
return d.getElementById(s);
}
function isObject(item) { function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item)); return (item && typeof item === 'object' && !Array.isArray(item));
} }
@ -164,22 +162,43 @@
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st || d.Sf.SU.checked != initial_su) d.Sf.submit(); if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st || d.Sf.SU.checked != initial_su) d.Sf.submit();
} }
function S() // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
{ function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
GetV(); GetV();
initial_ds = d.Sf.DS.value; initial_ds = d.Sf.DS.value;
initial_st = d.Sf.ST.checked; initial_st = d.Sf.ST.checked;
initial_su = d.Sf.SU.checked; initial_su = d.Sf.SU.checked;
GetLS(); GetLS();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
} }
function H() function S()
{ {
window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); if (window.location.protocol == "file:") {
loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
} }
function B()
{
window.open("/settings","_self");
} }
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=3';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
}
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
function B() { window.open("/settings","_self"); }
function UI() function UI()
{ {
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none'; gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
@ -214,7 +233,6 @@
fO.value = ''; fO.value = '';
return false; return false;
} }
function GetV(){var d=document;}
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>

View File

@ -192,7 +192,6 @@
e.preventDefault(); e.preventDefault();
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914 if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
} }
//fun-ction GetV() {} // replaced during 'npm run build'
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>

View File

@ -6,16 +6,44 @@
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>WiFi Settings</title> <title>WiFi Settings</title>
<script> <script>
var d=document;
var loc = false, locip;
function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");} function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");}
function B(){window.open("/settings","_self");} function B(){window.open("/settings","_self");}
function GetV() // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
{ function loadJS(FILE_URL, async = true) {
//values injected by server while sending HTML let scE = d.createElement("script");
scE.setAttribute("src", FILE_URL);
scE.setAttribute("type", "text/javascript");
scE.setAttribute("async", async);
d.body.appendChild(scE);
// success event
scE.addEventListener("load", () => {
//console.log("File loaded");
GetV();
});
// error event
scE.addEventListener("error", (ev) => {
console.log("Error on loading file", ev);
alert("Loading of configuration script failed.\nIncomplete page data!");
});
}
function S() {
if (window.location.protocol == "file:") {
loc = true;
locip = localStorage.getItem('locIp');
if (!locip) {
locip = prompt("File Mode. Please enter WLED IP!");
localStorage.setItem('locIp', locip);
}
}
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=1';
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
} }
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>
<body onload="GetV()"> <body onload="S()">
<form id="form_s" name="Sf" method="post"> <form id="form_s" name="Sf" method="post">
<div class="toprow"> <div class="toprow">
<div class="helpB"><button type="button" onclick="H()">?</button></div> <div class="helpB"><button type="button" onclick="H()">?</button></div>

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -89,7 +89,7 @@ byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte highe
void changeEffect(uint8_t fx) void changeEffect(uint8_t fx)
{ {
if (irApplyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
strip.setMode(i, fx); strip.setMode(i, fx);
@ -105,7 +105,7 @@ void changeEffect(uint8_t fx)
void changePalette(uint8_t pal) void changePalette(uint8_t pal)
{ {
if (irApplyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
seg.palette = pal; seg.palette = pal;
@ -124,7 +124,7 @@ void changeEffectSpeed(int8_t amount)
int16_t new_val = (int16_t) effectSpeed + amount; int16_t new_val = (int16_t) effectSpeed + amount;
effectSpeed = (byte)constrain(new_val,0,255); effectSpeed = (byte)constrain(new_val,0,255);
if (irApplyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
seg.speed = effectSpeed; seg.speed = effectSpeed;
@ -147,7 +147,7 @@ void changeEffectSpeed(int8_t amount)
prim_hsv.h = (byte)new_val; prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col); hsv2rgb_rainbow(prim_hsv, fastled_col);
if (irApplyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0])); seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
@ -171,7 +171,7 @@ void changeEffectIntensity(int8_t amount)
int16_t new_val = (int16_t) effectIntensity + amount; int16_t new_val = (int16_t) effectIntensity + amount;
effectIntensity = (byte)constrain(new_val,0,255); effectIntensity = (byte)constrain(new_val,0,255);
if (irApplyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
seg.intensity = effectIntensity; seg.intensity = effectIntensity;
@ -192,7 +192,7 @@ void changeEffectIntensity(int8_t amount)
prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255 prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255
hsv2rgb_rainbow(prim_hsv, fastled_col); hsv2rgb_rainbow(prim_hsv, fastled_col);
if (irApplyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0])); seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
@ -214,7 +214,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
{ {
if (irApplyToAllSelected) { if (irApplyToAllSelected) {
// main segment may not be selected! // main segment may not be selected!
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
byte capabilities = seg.getLightCapabilities(); byte capabilities = seg.getLightCapabilities();

View File

@ -11,11 +11,20 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
byte id = elem["id"] | it; byte id = elem["id"] | it;
if (id >= strip.getMaxSegments()) return; if (id >= strip.getMaxSegments()) return;
int stop = elem["stop"] | -1;
// if using vectors use this code to append segment
if (id >= strip.getActiveSegmentsNum()) {
if (stop <= 0) return; // ignore empty/inactive segments
DEBUG_PRINT(F("Adding segment: ")); DEBUG_PRINTLN(id);
strip.appendSegment(Segment(0, strip.getLengthTotal()));
id = strip.getActiveSegmentsNum()-1; // segments are added at the end of list
}
Segment& seg = strip.getSegment(id); Segment& seg = strip.getSegment(id);
Segment prev = seg; //make a backup so we can tell if something changed Segment prev = seg; //make a backup so we can tell if something changed
uint16_t start = elem["start"] | seg.start; uint16_t start = elem["start"] | seg.start;
int stop = elem["stop"] | -1;
if (stop < 0) { if (stop < 0) {
uint16_t len = elem["len"]; uint16_t len = elem["len"];
stop = (len > 0) ? start + len : seg.stop; stop = (len > 0) ? start + len : seg.stop;
@ -232,7 +241,6 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
// send UDP if not in preset and something changed that is not just selection // send UDP if not in preset and something changed that is not just selection
// send UDP if something changed that is not just selection or segment power/opacity // send UDP if something changed that is not just selection or segment power/opacity
if ((seg.differs(prev) & 0x7E) && seg.getOption(SEG_OPTION_ON)==prev.getOption(SEG_OPTION_ON)) stateChanged = true; if ((seg.differs(prev) & 0x7E) && seg.getOption(SEG_OPTION_ON)==prev.getOption(SEG_OPTION_ON)) stateChanged = true;
return;
} }
// deserializes WLED state (fileDoc points to doc object if called from web server) // deserializes WLED state (fileDoc points to doc object if called from web server)
@ -250,7 +258,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (root["on"].is<const char*>() && root["on"].as<const char*>()[0] == 't') toggleOnOff(); if (root["on"].is<const char*>() && root["on"].as<const char*>()[0] == 't') toggleOnOff();
if (bri && !onBefore) { // unfreeze all segments when turning on if (bri && !onBefore) { // unfreeze all segments when turning on
for (uint8_t s=0; s < strip.getMaxSegments(); s++) { for (uint8_t s=0; s < strip.getActiveSegmentsNum(); s++) {
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, false); strip.getSegment(s).setOption(SEG_OPTION_FREEZE, false);
} }
if (realtimeMode && !realtimeOverride && useMainSegmentOnly) { // keep live segment frozen if live if (realtimeMode && !realtimeOverride && useMainSegmentOnly) { // keep live segment frozen if live
@ -328,15 +336,13 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (id < 0) { if (id < 0) {
//apply all selected segments //apply all selected segments
//bool didSet = false; //bool didSet = false;
for (byte s = 0; s < strip.getMaxSegments(); s++) { for (byte s = 0; s < strip.getActiveSegmentsNum(); s++) {
Segment &sg = strip.getSegment(s); Segment &sg = strip.getSegment(s);
if (sg.isActive()) {
if (sg.isSelected()) { if (sg.isSelected()) {
deserializeSegment(segVar, s, presetId); deserializeSegment(segVar, s, presetId);
//didSet = true; //didSet = true;
} }
} }
}
//TODO: not sure if it is good idea to change first active but unselected segment //TODO: not sure if it is good idea to change first active but unselected segment
//if (!didSet) deserializeSegment(segVar, strip.getMainSegmentId(), presetId); //if (!didSet) deserializeSegment(segVar, strip.getMainSegmentId(), presetId);
} else { } else {
@ -346,9 +352,12 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
JsonArray segs = segVar.as<JsonArray>(); JsonArray segs = segVar.as<JsonArray>();
for (JsonObject elem : segs) for (JsonObject elem : segs)
{ {
DEBUG_PRINT(F(" Deserializing segment: ")); DEBUG_PRINTLN(it);
deserializeSegment(elem, it, presetId); deserializeSegment(elem, it, presetId);
it++; it++;
} }
// DEBUG_PRINTLN(F(" Purging segments."));
// strip.purgeSegments(); // prune inactive segments (resets ESP if effect running)
} }
usermods.readFromJsonState(root); usermods.readFromJsonState(root);
@ -496,8 +505,16 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
bool selectedSegmentsOnly = root[F("sc")] | false; bool selectedSegmentsOnly = root[F("sc")] | false;
JsonArray seg = root.createNestedArray("seg"); JsonArray seg = root.createNestedArray("seg");
for (byte s = 0; s < strip.getMaxSegments(); s++) { for (byte s = 0; s < strip.getMaxSegments(); s++) {
if (s >= strip.getActiveSegmentsNum()) {
if (forPreset && segmentBounds) { //disable segments not part of preset
JsonObject seg0 = seg.createNestedObject();
seg0["stop"] = 0;
continue;
} else
break;
}
Segment &sg = strip.getSegment(s); Segment &sg = strip.getSegment(s);
if (selectedSegmentsOnly && !sg.isSelected()) continue; if (!forPreset && selectedSegmentsOnly && !sg.isSelected()) continue;
if (sg.isActive()) { if (sg.isActive()) {
JsonObject seg0 = seg.createNestedObject(); JsonObject seg0 = seg.createNestedObject();
serializeSegment(seg0, sg, s, forPreset, segmentBounds); serializeSegment(seg0, sg, s, forPreset, segmentBounds);
@ -520,6 +537,7 @@ void serializeInfo(JsonObject root)
leds["fps"] = strip.getFps(); leds["fps"] = strip.getFps();
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
leds[F("maxseg")] = strip.getMaxSegments(); leds[F("maxseg")] = strip.getMaxSegments();
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
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D

View File

@ -31,7 +31,7 @@ void applyValuesToSelectedSegs()
// copy of first selected segment to tell if value was updated // copy of first selected segment to tell if value was updated
uint8_t firstSel = strip.getFirstSelectedSegId(); uint8_t firstSel = strip.getFirstSelectedSegId();
Segment selsegPrev = strip.getSegment(firstSel); Segment selsegPrev = strip.getSegment(firstSel);
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue; if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue;

View File

@ -84,7 +84,7 @@ void handlePresets(bool force)
presetToApply = 0; //clear request for preset presetToApply = 0; //clear request for preset
callModeToApply = 0; callModeToApply = 0;
DEBUG_PRINTLN(F("Applying preset: ")); DEBUG_PRINT(F("Applying preset: "));
DEBUG_PRINTLN(tmpPreset); DEBUG_PRINTLN(tmpPreset);
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32

View File

@ -608,7 +608,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SS=")); pos = req.indexOf(F("SS="));
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); byte t = getNumVal(&req, pos);
if (t < strip.getMaxSegments()) { if (t < strip.getActiveSegmentsNum()) {
selectedSeg = t; selectedSeg = t;
singleSegment = true; singleSegment = true;
} }
@ -618,7 +618,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SV=")); //segment selected pos = req.indexOf(F("SV=")); //segment selected
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); byte t = getNumVal(&req, pos);
if (t == 2) for (uint8_t i = 0; i < strip.getMaxSegments(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments if (t == 2) for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
selseg.setOption(SEG_OPTION_SELECTED, t); selseg.setOption(SEG_OPTION_SELECTED, t);
} }
@ -824,7 +824,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged); stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged);
// apply to main and all selected segments to prevent #1618. // apply to main and all selected segments to prevent #1618.
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all
if (fxModeChanged) strip.setMode(i, effectIn); if (fxModeChanged) strip.setMode(i, effectIn);

View File

@ -89,9 +89,9 @@ void notify(byte callMode, bool followUp)
udpOut[37] = strip.hasCCTBus() ? 0 : 255; //check this is 0 for the next value to be significant udpOut[37] = strip.hasCCTBus() ? 0 : 255; //check this is 0 for the next value to be significant
udpOut[38] = mainseg.cct; udpOut[38] = mainseg.cct;
udpOut[39] = strip.getMaxSegments(); udpOut[39] = strip.getActiveSegmentsNum();
udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment) udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment)
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment &selseg = strip.getSegment(i); Segment &selseg = strip.getSegment(i);
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
udpOut[0 +ofs] = i; udpOut[0 +ofs] = i;
@ -155,7 +155,7 @@ void realtimeLock(uint32_t timeoutMs, byte md)
for (uint16_t i = start; i < stop; i++) strip.setPixelColor(i,0,0,0,0); for (uint16_t i = start; i < stop; i++) strip.setPixelColor(i,0,0,0,0);
// if WLED was off and using main segment only, freeze non-main segments so they stay off // if WLED was off and using main segment only, freeze non-main segments so they stay off
if (useMainSegmentOnly && bri == 0) { if (useMainSegmentOnly && bri == 0) {
for (uint8_t s=0; s < strip.getMaxSegments(); s++) { for (uint8_t s=0; s < strip.getActiveSegmentsNum(); s++) {
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, true); strip.getSegment(s).setOption(SEG_OPTION_FREEZE, true);
} }
} }
@ -342,7 +342,7 @@ void handleNotifications()
for (uint8_t i = 0; i < numSrcSegs; i++) { for (uint8_t i = 0; i < numSrcSegs; i++) {
uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte
uint8_t id = udpIn[0 +ofs]; uint8_t id = udpIn[0 +ofs];
if (id > strip.getMaxSegments()) break; if (id > strip.getActiveSegmentsNum()) break;
Segment& selseg = strip.getSegment(id); Segment& selseg = strip.getSegment(id);
uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]); uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]);
uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]); uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
@ -377,7 +377,7 @@ void handleNotifications()
// simple effect sync, applies to all selected segments // simple effect sync, applies to all selected segments
if (applyEffects && (version < 11 || !receiveSegmentOptions)) { if (applyEffects && (version < 11 || !receiveSegmentOptions)) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getActiveSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
if (udpIn[8] < strip.getModeCount()) strip.setMode(i, udpIn[8]); if (udpIn[8] < strip.getModeCount()) strip.setMode(i, udpIn[8]);

View File

@ -118,6 +118,8 @@ void WLED::loop()
if (stripMillis > maxStripMillis) maxStripMillis = stripMillis; if (stripMillis > maxStripMillis) maxStripMillis = stripMillis;
#endif #endif
} }
if (offMode) strip.purgeSegments(); // remove inactive segments from memory (no effects running)
yield(); yield();
#ifdef ESP8266 #ifdef ESP8266
MDNS.update(); MDNS.update();

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2207081 #define VERSION 2207171
//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

View File

@ -154,7 +154,6 @@ void initServer()
}); });
server.on("/json", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/json", HTTP_GET, [](AsyncWebServerRequest *request){
while (strip.isUpdating()) delay(1);
serveJson(request); serveJson(request);
}); });
@ -162,8 +161,6 @@ void initServer()
bool verboseResponse = false; bool verboseResponse = false;
bool isConfig = false; bool isConfig = false;
while (strip.isUpdating()) delay(1);
if (!requestJSONBufferLock(14)) return; if (!requestJSONBufferLock(14)) return;
DeserializationError error = deserializeJson(doc, (uint8_t*)(request->_tempObject)); DeserializationError error = deserializeJson(doc, (uint8_t*)(request->_tempObject));

View File

@ -96,8 +96,6 @@ void sendDataWs(AsyncWebSocketClient * client)
if (!ws.count()) return; if (!ws.count()) return;
AsyncWebSocketMessageBuffer * buffer; AsyncWebSocketMessageBuffer * buffer;
while (strip.isUpdating()) delay(1);
if (!requestJSONBufferLock(12)) return; if (!requestJSONBufferLock(12)) return;
JsonObject state = doc.createNestedObject("state"); JsonObject state = doc.createNestedObject("state");