Merge branch 'main' into PJH_ADD_Linearbounce

This commit is contained in:
Blaz Kristan 2023-09-05 21:20:55 +02:00
commit 885f4ded0c
33 changed files with 3051 additions and 2671 deletions

View File

@ -1,5 +1,19 @@
## WLED changelog ## WLED changelog
#### Build 2308110
- Release of WLED beta version 0.14.0-b4 "Hoshi"
- Reset effect data immediately upon mode change
#### Build 2308030
- Improved random palette handling and blending
- Soap bugfix
- Fix ESP-NOW crash with AP mode Always
#### Build 2307180
- Bus-level global buffering (#3280)
- Removed per-segment LED buffer (SEGMENT.leds)
- various fixes and improvements (ESP variants platform 5.3.0, effect optimizations, /json/cfg pin allocation)
#### Build 2307130 #### Build 2307130
- larger `oappend()` stack buffer (3.5k) for ESP32 - larger `oappend()` stack buffer (3.5k) for ESP32
- Preset cycle bugfix (#3262) - Preset cycle bugfix (#3262)

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "wled", "name": "wled",
"version": "0.14.0-b3", "version": "0.14.0-b4",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "wled", "name": "wled",
"version": "0.14.0-b3", "version": "0.14.0-b4",
"description": "Tools for WLED project", "description": "Tools for WLED project",
"main": "tools/cdata.js", "main": "tools/cdata.js",
"directories": { "directories": {

View File

@ -433,6 +433,7 @@ platform_packages = ${esp32.platform_packages}
upload_speed = 921600 upload_speed = 921600
build_unflags = ${common.build_unflags} build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
-D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
lib_deps = ${esp32.lib_deps} lib_deps = ${esp32.lib_deps}
board_build.partitions = ${esp32.default_partitions} board_build.partitions = ${esp32.default_partitions}
@ -457,7 +458,7 @@ platform_packages = ${esp32c3.platform_packages}
framework = arduino framework = arduino
board = esp32-c3-devkitm-1 board = esp32-c3-devkitm-1
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3 build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=ESP32-C3
-D WLED_WATCHDOG_TIMEOUT=0 -D WLED_WATCHDOG_TIMEOUT=0
-DLOLIN_WIFI_FIX ; seems to work much better with this -DLOLIN_WIFI_FIX ; seems to work much better with this
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
@ -473,7 +474,7 @@ platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages} platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600 ; or 460800 upload_speed = 921600 ; or 460800
build_unflags = ${common.build_unflags} build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip -D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") ;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
@ -580,7 +581,7 @@ platform_packages = ${esp32s2.platform_packages}
board = lolin_s2_mini board = lolin_s2_mini
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
build_unflags = ${common.build_unflags} #-DARDUINO_USB_CDC_ON_BOOT=1 build_unflags = ${common.build_unflags} #-DARDUINO_USB_CDC_ON_BOOT=1
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2 build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2
-DBOARD_HAS_PSRAM -DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial -DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0

View File

@ -25,6 +25,7 @@ class Animated_Staircase : public Usermod {
bool useUSSensorBottom = false; // using PIR or UltraSound sensor? bool useUSSensorBottom = false; // using PIR or UltraSound sensor?
unsigned int topMaxDist = 50; // default maximum measured distance in cm, top unsigned int topMaxDist = 50; // default maximum measured distance in cm, top
unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom
bool togglePower = false; // toggle power on/off with staircase on/off
/* runtime variables */ /* runtime variables */
bool initDone = false; bool initDone = false;
@ -90,6 +91,7 @@ class Animated_Staircase : public Usermod {
static const char _bottomEcho_pin[]; static const char _bottomEcho_pin[];
static const char _topEchoCm[]; static const char _topEchoCm[];
static const char _bottomEchoCm[]; static const char _bottomEchoCm[];
static const char _togglePower[];
void publishMqtt(bool bottom, const char* state) { void publishMqtt(bool bottom, const char* state) {
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
@ -196,6 +198,7 @@ class Animated_Staircase : public Usermod {
if (on) { if (on) {
lastSensor = topSensorRead; lastSensor = topSensorRead;
} else { } else {
if (togglePower && onIndex == offIndex && offMode) toggleOnOff(); // toggle power on if off
// If the bottom sensor triggered, we need to swipe up, ON // If the bottom sensor triggered, we need to swipe up, ON
swipe = bottomSensorRead; swipe = bottomSensorRead;
@ -249,7 +252,10 @@ class Animated_Staircase : public Usermod {
offIndex = MAX(onIndex, offIndex - 1); offIndex = MAX(onIndex, offIndex - 1);
} }
} }
if (oldOn != onIndex || oldOff != offIndex) updateSegments(); // reduce the number of updates to necessary ones if (oldOn != onIndex || oldOff != offIndex) {
updateSegments(); // reduce the number of updates to necessary ones
if (togglePower && onIndex == offIndex && !offMode && !on) toggleOnOff(); // toggle power off for all segments off
}
} }
} }
@ -295,6 +301,7 @@ class Animated_Staircase : public Usermod {
strip.setTransition(segment_delay_ms/100); strip.setTransition(segment_delay_ms/100);
strip.trigger(); strip.trigger();
} else { } else {
if (togglePower && !on && offMode) toggleOnOff(); // toggle power on if off
// Restore segment options // Restore segment options
for (int i = 0; i <= strip.getLastActiveSegmentId(); i++) { for (int i = 0; i <= strip.getLastActiveSegmentId(); i++) {
Segment &seg = strip.getSegment(i); Segment &seg = strip.getSegment(i);
@ -444,6 +451,7 @@ class Animated_Staircase : public Usermod {
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1; staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
staircase[FPSTR(_topEchoCm)] = topMaxDist; staircase[FPSTR(_topEchoCm)] = topMaxDist;
staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist; staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist;
staircase[FPSTR(_togglePower)] = togglePower;
DEBUG_PRINTLN(F("Staircase config saved.")); DEBUG_PRINTLN(F("Staircase config saved."));
} }
@ -488,6 +496,8 @@ class Animated_Staircase : public Usermod {
bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist; bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist;
bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected) bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)
togglePower = top[FPSTR(_togglePower)] | togglePower; // staircase toggles power on/off
DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINT(FPSTR(_name));
if (!initDone) { if (!initDone) {
// first run: reading from cfg.json // first run: reading from cfg.json
@ -511,7 +521,7 @@ class Animated_Staircase : public Usermod {
if (changed) setup(); if (changed) setup();
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return true; return !top[FPSTR(_togglePower)].isNull();
} }
/* /*
@ -551,3 +561,4 @@ const char Animated_Staircase::_bottomPIRorTrigger_pin[] PROGMEM = "bottomPIR
const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin"; const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin";
const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm"; const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm";
const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm"; const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm";
const char Animated_Staircase::_togglePower[] PROGMEM = "toggle-on-off";

View File

@ -0,0 +1,17 @@
# Internal Temperature Usermod
This usermod adds the temperature readout to the Info tab and also publishes that over the topic `mcutemp` topic.
## Important
A shown temp of 53,33°C might indicate that the internal temp is not supported.
ESP8266 does not have a internal temp sensor
ESP32S2 seems to crash on reading the sensor -> disabled
## Installation
Add a build flag `-D USERMOD_INTERNAL_TEMPERATURE` to your `platformio.ini` (or `platformio_override.ini`).
## Authors
Soeren Willrodt [@lost-hope](https://github.com/lost-hope)
Dimitry Zhemkov [@dima-zhemkov](https://github.com/dima-zhemkov)

View File

@ -0,0 +1,117 @@
#pragma once
#include "wled.h"
class InternalTemperatureUsermod : public Usermod
{
private:
unsigned long loopInterval = 10000;
unsigned long lastTime = 0;
bool isEnabled = false;
float temperature = 0;
static const char _name[];
static const char _enabled[];
static const char _loopInterval[];
// any private methods should go here (non-inline methosd should be defined out of class)
void publishMqtt(const char *state, bool retain = false); // example for publishing MQTT message
public:
void setup()
{
}
void loop()
{
// if usermod is disabled or called during strip updating just exit
// NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
if (!isEnabled || strip.isUpdating() || millis() - lastTime <= loopInterval)
return;
lastTime = millis();
#ifdef ESP8266 // ESP8266
// does not seem possible
temperature = -1;
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32S2
temperature = -1;
#else // ESP32 ESP32S3 and ESP32C3
temperature = roundf(temperatureRead() * 10) / 10;
#endif
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED)
{
char array[10];
snprintf(array, sizeof(array), "%f", temperature);
publishMqtt(array);
}
#endif
}
void addToJsonInfo(JsonObject &root)
{
if (!isEnabled)
return;
// if "u" object does not exist yet wee need to create it
JsonObject user = root["u"];
if (user.isNull())
user = root.createNestedObject("u");
JsonArray userTempArr = user.createNestedArray(FPSTR(_name));
userTempArr.add(temperature);
userTempArr.add(F(" °C"));
// if "sensor" object does not exist yet wee need to create it
JsonObject sensor = root[F("sensor")];
if (sensor.isNull())
sensor = root.createNestedObject(F("sensor"));
JsonArray sensorTempArr = sensor.createNestedArray(FPSTR(_name));
sensorTempArr.add(temperature);
sensorTempArr.add(F("°C"));
}
void addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name));
top[FPSTR(_enabled)] = isEnabled;
top[FPSTR(_loopInterval)] = loopInterval;
}
bool readFromConfig(JsonObject &root)
{
JsonObject top = root[FPSTR(_name)];
bool configComplete = !top.isNull();
configComplete &= getJsonValue(top[FPSTR(_enabled)], isEnabled);
configComplete &= getJsonValue(top[FPSTR(_loopInterval)], loopInterval);
return configComplete;
}
uint16_t getId()
{
return USERMOD_ID_INTERNAL_TEMPERATURE;
}
};
const char InternalTemperatureUsermod::_name[] PROGMEM = "Internal Temperature";
const char InternalTemperatureUsermod::_enabled[] PROGMEM = "Enabled";
const char InternalTemperatureUsermod::_loopInterval[] PROGMEM = "Loop Interval";
void InternalTemperatureUsermod::publishMqtt(const char *state, bool retain)
{
#ifndef WLED_DISABLE_MQTT
// Check if MQTT Connected, otherwise it will crash the 8266
if (WLED_MQTT_CONNECTED)
{
char subuf[64];
strcpy(subuf, mqttDeviceTopic);
strcat_P(subuf, PSTR("/mcutemp"));
mqtt->publish(subuf, 0, retain, state);
}
#endif
}

View File

@ -1081,7 +1081,7 @@ bool FourLineDisplayUsermod::handleButton(uint8_t b) {
static bool buttonLongPressed = false; static bool buttonLongPressed = false;
static unsigned long buttonPressedTime = 0; static unsigned long buttonPressedTime = 0;
static unsigned long buttonWaitTime = 0; static unsigned long buttonWaitTime = 0;
bool handled = true; bool handled = false;
//momentary button logic //momentary button logic
if (isButtonPressed(b)) { //pressed if (isButtonPressed(b)) { //pressed
@ -1090,11 +1090,12 @@ bool FourLineDisplayUsermod::handleButton(uint8_t b) {
buttonPressedBefore = true; buttonPressedBefore = true;
if (now - buttonPressedTime > 600) { //long press if (now - buttonPressedTime > 600) { //long press
buttonLongPressed = true;
//TODO: handleButton() handles button 0 without preset in a different way for double click //TODO: handleButton() handles button 0 without preset in a different way for double click
//so we need to override with same behaviour //so we need to override with same behaviour
longPressAction(0); //DEBUG_PRINTLN(F("4LD action."));
//handled = false; //if (!buttonLongPressed) longPressAction(0);
buttonLongPressed = true;
return false;
} }
} else if (!isButtonPressed(b) && buttonPressedBefore) { //released } else if (!isButtonPressed(b) && buttonPressedBefore) { //released
@ -1126,7 +1127,7 @@ bool FourLineDisplayUsermod::handleButton(uint8_t b) {
buttonWaitTime = 0; buttonWaitTime = 0;
//TODO: handleButton() handles button 0 without preset in a different way for double click //TODO: handleButton() handles button 0 without preset in a different way for double click
//so we need to override with same behaviour //so we need to override with same behaviour
shortPressAction(0); //shortPressAction(0);
//handled = false; //handled = false;
} }
return handled; return handled;

View File

@ -398,8 +398,14 @@ void RotaryEncoderUIUsermod::sortModesAndPalettes() {
modes_alpha_indexes = re_initIndexArray(strip.getModeCount()); modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT); re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT);
palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount()); palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount()+strip.customPalettes.size());
palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()); // only use internal palettes palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()+strip.customPalettes.size());
if (strip.customPalettes.size()) {
for (int i=0; i<strip.customPalettes.size(); i++) {
palettes_alpha_indexes[strip.getPaletteCount()+i] = 255-i;
palettes_qstrings[strip.getPaletteCount()+i] = PSTR("~Custom~");
}
}
// How many palette names start with '*' and should not be sorted? // How many palette names start with '*' and should not be sorted?
// (Also skipping the first one, 'Default'). // (Also skipping the first one, 'Default').
@ -496,7 +502,7 @@ void RotaryEncoderUIUsermod::setup()
} }
} else { } else {
PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } }; PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } };
if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) { if (pinA<0 || pinB<0 || !pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) {
pinA = pinB = pinC = -1; pinA = pinB = pinC = -1;
enabled = false; enabled = false;
return; return;
@ -507,7 +513,7 @@ void RotaryEncoderUIUsermod::setup()
#endif #endif
pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO); pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO);
pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO); pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO);
pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO); if (pinC>=0) pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO);
} }
loopTime = millis(); loopTime = millis();
@ -682,21 +688,25 @@ void RotaryEncoderUIUsermod::displayNetworkInfo() {
void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() { void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() {
DEBUG_PRINTLN(F("Finding current mode and palette.")); DEBUG_PRINTLN(F("Finding current mode and palette."));
currentEffectAndPaletteInitialized = true; currentEffectAndPaletteInitialized = true;
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
effectCurrentIndex = 0;
for (int i = 0; i < strip.getModeCount(); i++) {
if (modes_alpha_indexes[i] == effectCurrent) { if (modes_alpha_indexes[i] == effectCurrent) {
effectCurrentIndex = i; effectCurrentIndex = i;
DEBUG_PRINTLN(F("Found current mode."));
break; break;
} }
} }
DEBUG_PRINTLN(F("Found current mode."));
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) { effectPaletteIndex = 0;
DEBUG_PRINTLN(effectPalette);
for (uint8_t i = 0; i < strip.getPaletteCount()+strip.customPalettes.size(); i++) {
if (palettes_alpha_indexes[i] == effectPalette) { if (palettes_alpha_indexes[i] == effectPalette) {
effectPaletteIndex = i; effectPaletteIndex = i;
DEBUG_PRINTLN(F("Found palette."));
break; break;
} }
} }
DEBUG_PRINTLN(F("Found palette."));
} }
bool RotaryEncoderUIUsermod::changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) { bool RotaryEncoderUIUsermod::changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) {
@ -731,7 +741,9 @@ void RotaryEncoderUIUsermod::changeBrightness(bool increase) {
} }
display->updateRedrawTime(); display->updateRedrawTime();
#endif #endif
bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0); //bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0);
if (bri < 40) bri = max(min((increase ? bri+fadeAmount/2 : bri-fadeAmount/2), 255), 0); // slower steps when brightness < 16%
else bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0);
lampUdated(); lampUdated();
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
display->updateBrightness(); display->updateBrightness();
@ -878,7 +890,7 @@ void RotaryEncoderUIUsermod::changePalette(bool increase) {
} }
display->updateRedrawTime(); display->updateRedrawTime();
#endif #endif
effectPaletteIndex = max(min((increase ? effectPaletteIndex+1 : effectPaletteIndex-1), strip.getPaletteCount()-1), 0); effectPaletteIndex = max(min((unsigned)(increase ? effectPaletteIndex+1 : effectPaletteIndex-1), strip.getPaletteCount()+strip.customPalettes.size()-1), 0U);
effectPalette = palettes_alpha_indexes[effectPaletteIndex]; effectPalette = palettes_alpha_indexes[effectPaletteIndex];
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {

View File

@ -604,11 +604,6 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0";
* Dissolve function * Dissolve function
*/ */
uint16_t dissolve(uint32_t color) { uint16_t dissolve(uint32_t color) {
//bool wa = (SEGCOLOR(1) != 0 && strip.getBrightness() < 255); //workaround, can't compare getPixel to color if not full brightness
if (SEGENV.call == 0) {
SEGMENT.fill(SEGCOLOR(1));
}
for (int j = 0; j <= SEGLEN / 15; j++) { for (int j = 0; j <= SEGLEN / 15; j++) {
if (random8() <= SEGMENT.intensity) { if (random8() <= SEGMENT.intensity) {
for (size_t times = 0; times < 10; times++) //attempt to spawn a new pixel 10 times for (size_t times = 0; times < 10; times++) //attempt to spawn a new pixel 10 times
@ -713,7 +708,7 @@ uint16_t mode_hyper_sparkle(void) {
if (strip.now - SEGENV.aux0 > SEGENV.step) { if (strip.now - SEGENV.aux0 > SEGENV.step) {
if (random8((255-SEGMENT.intensity) >> 4) == 0) { if (random8((255-SEGMENT.intensity) >> 4) == 0) {
for (int i = 0; i < MAX(1, SEGLEN/3); i++) { for (int i = 0; i < max(1, SEGLEN/3); i++) {
SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1));
} }
} }
@ -764,7 +759,7 @@ uint16_t mode_android(void) {
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
} }
if (SEGENV.aux1 > ((float)SEGMENT.intensity/255.0)*(float)SEGLEN) if (SEGENV.aux1 > (SEGMENT.intensity*SEGLEN)/255)
{ {
SEGENV.aux0 = 1; SEGENV.aux0 = 1;
} else } else
@ -814,7 +809,7 @@ static const char _data_FX_MODE_ANDROID[] PROGMEM = "Android@!,Width;!,!;!;;m12=
*/ */
uint16_t chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palette) { uint16_t chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palette) {
uint16_t counter = strip.now * ((SEGMENT.speed >> 2) + 1); uint16_t counter = strip.now * ((SEGMENT.speed >> 2) + 1);
uint16_t a = counter * SEGLEN >> 16; uint16_t a = (counter * SEGLEN) >> 16;
bool chase_random = (SEGMENT.mode == FX_MODE_CHASE_RANDOM); bool chase_random = (SEGMENT.mode == FX_MODE_CHASE_RANDOM);
if (chase_random) { if (chase_random) {
@ -828,7 +823,7 @@ uint16_t chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palett
SEGENV.step = a; SEGENV.step = a;
// Use intensity setting to vary chase up to 1/2 string length // Use intensity setting to vary chase up to 1/2 string length
uint8_t size = 1 + (SEGMENT.intensity * SEGLEN >> 10); uint8_t size = 1 + ((SEGMENT.intensity * SEGLEN) >> 10);
uint16_t b = a + size; //"trail" of chase, filled with color1 uint16_t b = a + size; //"trail" of chase, filled with color1
if (b > SEGLEN) b -= SEGLEN; if (b > SEGLEN) b -= SEGLEN;
@ -1116,8 +1111,9 @@ static const char _data_FX_MODE_RUNNING_RANDOM[] PROGMEM = "Stream@!,Zone size;;
uint16_t larson_scanner(bool dual) { uint16_t larson_scanner(bool dual) {
if (SEGLEN == 1) return mode_static();
uint16_t counter = strip.now * ((SEGMENT.speed >> 2) +8); uint16_t counter = strip.now * ((SEGMENT.speed >> 2) +8);
uint16_t index = counter * SEGLEN >> 16; uint16_t index = (counter * SEGLEN) >> 16;
SEGMENT.fade_out(SEGMENT.intensity); SEGMENT.fade_out(SEGMENT.intensity);
@ -1204,7 +1200,6 @@ uint16_t mode_fireworks() {
const uint16_t height = SEGMENT.virtualHeight(); const uint16_t height = SEGMENT.virtualHeight();
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGMENT.fill(SEGCOLOR(1));
SEGENV.aux0 = UINT16_MAX; SEGENV.aux0 = UINT16_MAX;
SEGENV.aux1 = UINT16_MAX; SEGENV.aux1 = UINT16_MAX;
} }
@ -1220,7 +1215,7 @@ uint16_t mode_fireworks() {
if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
for (int i=0; i<MAX(1, width/20); i++) { for (int i=0; i<max(1, width/20); i++) {
if (random8(129 - (SEGMENT.intensity >> 1)) == 0) { if (random8(129 - (SEGMENT.intensity >> 1)) == 0) {
uint16_t index = random16(width*height); uint16_t index = random16(width*height);
x = index % width; x = index % width;
@ -1305,24 +1300,23 @@ static const char _data_FX_MODE_FIRE_FLICKER[] PROGMEM = "Fire Flicker@!,!;!;!;0
* Gradient run base function * Gradient run base function
*/ */
uint16_t gradient_base(bool loading) { uint16_t gradient_base(bool loading) {
if (SEGLEN == 1) return mode_static();
uint16_t counter = strip.now * ((SEGMENT.speed >> 2) + 1); uint16_t counter = strip.now * ((SEGMENT.speed >> 2) + 1);
uint16_t pp = counter * SEGLEN >> 16; uint16_t pp = (counter * SEGLEN) >> 16;
if (SEGENV.call == 0) pp = 0; if (SEGENV.call == 0) pp = 0;
float val; //0.0 = sec 1.0 = pri int val; //0 = sec 1 = pri
float brd = loading ? SEGMENT.intensity : SEGMENT.intensity/2; int brd = 1 + loading ? SEGMENT.intensity/2 : SEGMENT.intensity/4;
if (brd <1.0) brd = 1.0; //if (brd < 1) brd = 1;
int p1 = pp-SEGLEN; int p1 = pp-SEGLEN;
int p2 = pp+SEGLEN; int p2 = pp+SEGLEN;
for (int i = 0; i < SEGLEN; i++) for (int i = 0; i < SEGLEN; i++) {
{ if (loading) {
if (loading) val = abs(((i>pp) ? p2:pp) - i);
{
val = abs(((i>pp) ? p2:pp) -i);
} else { } else {
val = MIN(abs(pp-i),MIN(abs(p1-i),abs(p2-i))); val = min(abs(pp-i),min(abs(p1-i),abs(p2-i)));
} }
val = (brd > val) ? val/brd * 255 : 255; val = (brd > val) ? (val * 255) / brd : 255;
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val));
} }
@ -1903,12 +1897,8 @@ static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
//eight colored dots, weaving in and out of sync with each other //eight colored dots, weaving in and out of sync with each other
uint16_t mode_juggle(void) { uint16_t mode_juggle(void) {
if (SEGLEN == 1) return mode_static(); if (SEGLEN == 1) return mode_static();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(192 - (3*SEGMENT.intensity/4)); SEGMENT.fadeToBlackBy(192 - (3*SEGMENT.intensity/4));
CRGB fastled_col; CRGB fastled_col;
byte dothue = 0; byte dothue = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
@ -2073,12 +2063,9 @@ static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!";
// colored stripes pulsing at a defined Beats-Per-Minute (BPM) // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
uint16_t mode_bpm() { uint16_t mode_bpm() {
//CRGB fastled_col;
uint32_t stp = (strip.now / 20) & 0xFF; uint32_t stp = (strip.now / 20) & 0xFF;
uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); uint8_t beat = beatsin8(SEGMENT.speed, 64, 255);
for (int i = 0; i < SEGLEN; i++) { for (int i = 0; i < SEGLEN; i++) {
//fastled_col = ColorFromPalette(SEGPALETTE, stp + (i * 2), beat - stp + (i * 10));
//SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10)));
} }
@ -2475,12 +2462,6 @@ static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wav
// //
// TwinkleFOX: Twinkling 'holiday' lights that fade in and out. // TwinkleFOX: Twinkling 'holiday' lights that fade in and out.
// Colors are chosen from a palette. Read more about this effect using the link above! // Colors are chosen from a palette. Read more about this effect using the link above!
// If COOL_LIKE_INCANDESCENT is set to 1, colors will
// fade out slighted 'reddened', similar to how
// incandescent bulbs change color as they get dim down.
#define COOL_LIKE_INCANDESCENT 1
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
{ {
// Overall twinkle speed (changed) // Overall twinkle speed (changed)
@ -2519,7 +2500,7 @@ CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
CRGB c; CRGB c;
if (bright > 0) { if (bright > 0) {
c = ColorFromPalette(SEGPALETTE, hue, bright, NOBLEND); c = ColorFromPalette(SEGPALETTE, hue, bright, NOBLEND);
if(COOL_LIKE_INCANDESCENT == 1) { if (!SEGMENT.check1) {
// This code takes a pixel, and if its in the 'fading down' // This code takes a pixel, and if its in the 'fading down'
// part of the cycle, it adjusts the color a little bit like the // part of the cycle, it adjusts the color a little bit like the
// way that incandescent bulbs fade toward 'red' as they dim. // way that incandescent bulbs fade toward 'red' as they dim.
@ -2605,14 +2586,14 @@ uint16_t mode_twinklefox()
{ {
return twinklefox_base(false); return twinklefox_base(false);
} }
static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate;;!"; static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate,,,,Cool;;!";
uint16_t mode_twinklecat() uint16_t mode_twinklecat()
{ {
return twinklefox_base(true); return twinklefox_base(true);
} }
static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate;;!"; static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate,,,,Cool;;!";
//inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes //inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes
@ -2877,8 +2858,10 @@ static uint16_t rolling_balls(void) {
// number of balls based on intensity setting to max of 16 (cycles colors) // number of balls based on intensity setting to max of 16 (cycles colors)
// non-chosen color is a random color // non-chosen color is a random color
uint8_t numBalls = SEGMENT.intensity/16 + 1; uint8_t numBalls = SEGMENT.intensity/16 + 1;
bool hasCol2 = SEGCOLOR(2);
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); // start clean
for (int i = 0; i < maxNumBalls; i++) { for (int i = 0; i < maxNumBalls; i++) {
balls[i].lastBounceUpdate = strip.now; balls[i].lastBounceUpdate = strip.now;
balls[i].velocity = 20.0f * float(random16(1000, 10000))/10000.0f; // number from 1 to 10 balls[i].velocity = 20.0f * float(random16(1000, 10000))/10000.0f; // number from 1 to 10
@ -2890,14 +2873,16 @@ static uint16_t rolling_balls(void) {
float cfac = float(scale8(8, 255-SEGMENT.speed) +1)*20000.0f; // this uses the Aircoookie conversion factor for scaling time using speed slider float cfac = float(scale8(8, 255-SEGMENT.speed) +1)*20000.0f; // this uses the Aircoookie conversion factor for scaling time using speed slider
bool hasCol2 = SEGCOLOR(2); if (SEGMENT.check3) SEGMENT.fade_out(250); // 2-8 pixel trails (optional)
if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); else {
if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); // don't fill with background color if user wants to see trails
}
for (int i = 0; i < numBalls; i++) { for (int i = 0; i < numBalls; i++) {
float timeSinceLastUpdate = float((strip.now - balls[i].lastBounceUpdate))/cfac; float timeSinceLastUpdate = float((strip.now - balls[i].lastBounceUpdate))/cfac;
float thisHeight = balls[i].height + balls[i].velocity * timeSinceLastUpdate; // this method keeps higher resolution float thisHeight = balls[i].height + balls[i].velocity * timeSinceLastUpdate; // this method keeps higher resolution
// test if intensity level was increased and some balls are way off the track then put them back // test if intensity level was increased and some balls are way off the track then put them back
if (thisHeight < -0.5f || thisHeight > 1.5f){ if (thisHeight < -0.5f || thisHeight > 1.5f) {
thisHeight = balls[i].height = (float(random16(0, 10000)) / 10000.0f); // from 0. to 1. thisHeight = balls[i].height = (float(random16(0, 10000)) / 10000.0f); // from 0. to 1.
balls[i].lastBounceUpdate = strip.now; balls[i].lastBounceUpdate = strip.now;
} }
@ -2947,7 +2932,7 @@ static uint16_t rolling_balls(void) {
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of balls,,,,Collisions,Overlay;!,!,!;!;1;m12=1"; //bar static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of balls,,,,Collisions,Overlay,Trails;!,!,!;!;1;m12=1"; //bar
/* /*
@ -3027,7 +3012,7 @@ uint16_t mode_glitter()
static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;1,2,Glitter color;!;;pal=0,m12=0"; //pixels static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;1,2,Glitter color;!;;pal=0,m12=0"; //pixels
//Solid colour background with glitter //Solid colour background with glitter (can be replaced by Glitter)
uint16_t mode_solid_glitter() uint16_t mode_solid_glitter()
{ {
SEGMENT.fill(SEGCOLOR(0)); SEGMENT.fill(SEGCOLOR(0));
@ -3117,10 +3102,9 @@ static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!,,,,,Overlay;!,!
uint16_t candle(bool multi) uint16_t candle(bool multi)
{ {
if (multi) if (multi && SEGLEN > 1) {
{
//allocate segment data //allocate segment data
uint16_t dataSize = (SEGLEN -1) *3; //max. 1365 pixels (ESP8266) uint16_t dataSize = max(1, SEGLEN -1) *3; //max. 1365 pixels (ESP8266)
if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed
} }
@ -3253,7 +3237,7 @@ uint16_t mode_starburst(void) {
if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0)
{ {
// Pick a random color and location. // Pick a random color and location.
uint16_t startPos = random16(SEGLEN-1); uint16_t startPos = (SEGLEN > 1) ? random16(SEGLEN-1) : 0;
float multiplier = (float)(random8())/255.0 * 1.0; float multiplier = (float)(random8())/255.0 * 1.0;
stars[j].color = CRGB(SEGMENT.color_wheel(random8())); stars[j].color = CRGB(SEGMENT.color_wheel(random8()));
@ -3497,7 +3481,7 @@ uint16_t mode_drip(void)
uint8_t numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3 uint8_t numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
float gravity = -0.0005 - (SEGMENT.speed/50000.0); float gravity = -0.0005 - (SEGMENT.speed/50000.0);
gravity *= SEGLEN-1; gravity *= max(1, SEGLEN-1);
int sourcedrop = 12; int sourcedrop = 12;
for (int j=0;j<numDrops;j++) { for (int j=0;j<numDrops;j++) {
@ -3687,8 +3671,8 @@ uint16_t mode_percent(void) {
uint8_t percent = SEGMENT.intensity; uint8_t percent = SEGMENT.intensity;
percent = constrain(percent, 0, 200); percent = constrain(percent, 0, 200);
uint16_t active_leds = (percent < 100) ? SEGLEN * percent / 100.0 uint16_t active_leds = (percent < 100) ? roundf(SEGLEN * percent / 100.0f)
: SEGLEN * (200 - percent) / 100.0; : roundf(SEGLEN * (200 - percent) / 100.0f);
uint8_t size = (1 + ((SEGMENT.speed * SEGLEN) >> 11)); uint8_t size = (1 + ((SEGMENT.speed * SEGLEN) >> 11));
if (SEGMENT.speed == 255) size = 255; if (SEGMENT.speed == 255) size = 255;
@ -4679,11 +4663,6 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
uint16_t x, y; uint16_t x, y;
// initialize on first call
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails
unsigned long t = millis()/128; // timebase unsigned long t = millis()/128; // timebase
// outer stars // outer stars
@ -4718,7 +4697,6 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
SEGENV.aux0 = 0; // start with red hue SEGENV.aux0 = 0; // start with red hue
} }
@ -4770,12 +4748,7 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(64); SEGMENT.fadeToBlackBy(64);
for (int i = 0; i < cols; i++) { for (int i = 0; i < cols; i++) {
SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+millis()/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+millis()/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND));
SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+millis()/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+millis()/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND));
@ -4841,12 +4814,7 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(128); SEGMENT.fadeToBlackBy(128);
const uint16_t maxDim = MAX(cols, rows)/2; const uint16_t maxDim = MAX(cols, rows)/2;
unsigned long t = millis() / (32 - (SEGMENT.speed>>3)); unsigned long t = millis() / (32 - (SEGMENT.speed>>3));
unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup
@ -4906,10 +4874,6 @@ uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.so
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(16); SEGMENT.fadeToBlackBy(16);
for (size_t i = 8; i > 0; i--) { for (size_t i = 8; i > 0; i--) {
SEGMENT.addPixelColorXY(beatsin8(SEGMENT.speed/8 + i, 0, cols - 1), SEGMENT.addPixelColorXY(beatsin8(SEGMENT.speed/8 + i, 0, cols - 1),
@ -5353,12 +5317,7 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2); SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2);
uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float
for (int i = 0; i < cols; i++) { for (int i = 0; i < cols; i++) {
uint16_t thisVal = inoise8(i * 30, t, t); uint16_t thisVal = inoise8(i * 30, t, t);
@ -5449,12 +5408,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5)); SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5));
uint32_t a = strip.now / (18 - SEGMENT.speed / 16); uint32_t a = strip.now / (18 - SEGMENT.speed / 16);
uint16_t x = (a / 14) % cols; uint16_t x = (a / 14) % cols;
uint16_t y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0); uint16_t y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0);
@ -5507,14 +5461,9 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
const uint8_t kBorderWidth = 2; const uint8_t kBorderWidth = 2;
SEGMENT.fadeToBlackBy(24); SEGMENT.fadeToBlackBy(24);
uint8_t blurAmount = SEGMENT.custom3>>1; // reduced resolution slider uint8_t blurAmount = SEGMENT.custom3>>1; // reduced resolution slider
SEGMENT.blur(blurAmount); SEGMENT.blur(blurAmount);
@ -5635,10 +5584,6 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
uint32_t tb = strip.now >> 12; // every ~4s uint32_t tb = strip.now >> 12; // every ~4s
if (tb > SEGENV.step) { if (tb > SEGENV.step) {
int8_t dir = ++SEGENV.aux0; int8_t dir = ++SEGENV.aux0;
@ -5704,7 +5649,6 @@ uint16_t mode_2Dcrazybees(void) {
bee_t *bee = reinterpret_cast<bee_t*>(SEGENV.data); bee_t *bee = reinterpret_cast<bee_t*>(SEGENV.data);
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
bee[i].posX = random8(0, cols); bee[i].posX = random8(0, cols);
bee[i].posY = random8(0, rows); bee[i].posY = random8(0, rows);
@ -5713,7 +5657,7 @@ uint16_t mode_2Dcrazybees(void) {
} }
if (millis() > SEGENV.step) { if (millis() > SEGENV.step) {
SEGENV.step = millis() + (FRAMETIME * 8 / ((SEGMENT.speed>>5)+1)); SEGENV.step = millis() + (FRAMETIME * 16 / ((SEGMENT.speed>>4)+1));
SEGMENT.fadeToBlackBy(32); SEGMENT.fadeToBlackBy(32);
@ -5776,9 +5720,9 @@ uint16_t mode_2Dghostrider(void) {
if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) { if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
SEGENV.aux0 = cols; SEGENV.aux0 = cols;
SEGENV.aux1 = rows; SEGENV.aux1 = rows;
SEGMENT.fill(BLACK);
random16_set_seed(strip.now); random16_set_seed(strip.now);
lighter->angleSpeed = random8(0,20) - 10; lighter->angleSpeed = random8(0,20) - 10;
lighter->gAngle = random16();
lighter->Vspeed = 5; lighter->Vspeed = 5;
lighter->gPosX = (cols/2) * 10; lighter->gPosX = (cols/2) * 10;
lighter->gPosY = (rows/2) * 10; lighter->gPosY = (rows/2) * 10;
@ -5786,6 +5730,7 @@ uint16_t mode_2Dghostrider(void) {
lighter->lightersPosX[i] = lighter->gPosX; lighter->lightersPosX[i] = lighter->gPosX;
lighter->lightersPosY[i] = lighter->gPosY + i; lighter->lightersPosY[i] = lighter->gPosY + i;
lighter->time[i] = i * 2; lighter->time[i] = i * 2;
lighter->reg[i] = false;
} }
} }
@ -5860,7 +5805,7 @@ uint16_t mode_2Dfloatingblobs(void) {
if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) { if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
SEGENV.aux0 = cols; // re-initialise if virtual size changes SEGENV.aux0 = cols; // re-initialise if virtual size changes
SEGENV.aux1 = rows; SEGENV.aux1 = rows;
SEGMENT.fill(BLACK); //SEGMENT.fill(BLACK);
for (size_t i = 0; i < MAX_BLOBS; i++) { for (size_t i = 0; i < MAX_BLOBS; i++) {
blob->r[i] = random8(1, cols>8 ? (cols/4) : 2); blob->r[i] = random8(1, cols>8 ? (cols/4) : 2);
blob->sX[i] = (float) random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x blob->sX[i] = (float) random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x
@ -5874,7 +5819,7 @@ uint16_t mode_2Dfloatingblobs(void) {
} }
} }
SEGMENT.fadeToBlackBy(20); SEGMENT.fadeToBlackBy((SEGMENT.custom2>>3)+1);
// Bounce balls around // Bounce balls around
for (size_t i = 0; i < Amount; i++) { for (size_t i = 0; i < Amount; i++) {
@ -5930,7 +5875,7 @@ uint16_t mode_2Dfloatingblobs(void) {
return FRAMETIME; return FRAMETIME;
} }
#undef MAX_BLOBS #undef MAX_BLOBS
static const char _data_FX_MODE_2DBLOBS[] PROGMEM = "Blobs@!,# blobs,Blur;!;!;2;c1=8"; static const char _data_FX_MODE_2DBLOBS[] PROGMEM = "Blobs@!,# blobs,Blur,Trail;!;!;2;c1=8";
//////////////////////////// ////////////////////////////
@ -5942,8 +5887,8 @@ uint16_t mode_2Dscrollingtext(void) {
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
int letterWidth; int letterWidth, rotLW;
int letterHeight; int letterHeight, rotLH;
switch (map(SEGMENT.custom2, 0, 255, 1, 5)) { switch (map(SEGMENT.custom2, 0, 255, 1, 5)) {
default: default:
case 1: letterWidth = 4; letterHeight = 6; break; case 1: letterWidth = 4; letterHeight = 6; break;
@ -5952,59 +5897,84 @@ uint16_t mode_2Dscrollingtext(void) {
case 4: letterWidth = 7; letterHeight = 9; break; case 4: letterWidth = 7; letterHeight = 9; break;
case 5: letterWidth = 5; letterHeight = 12; break; case 5: letterWidth = 5; letterHeight = 12; break;
} }
const bool zero = SEGMENT.check3; // letters are rotated
const int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-letterHeight)/2; if (((SEGMENT.custom3+1)>>3) % 2) {
rotLH = letterWidth;
rotLW = letterHeight;
} else {
rotLW = letterWidth;
rotLH = letterHeight;
}
char text[WLED_MAX_SEGNAME_LEN+1] = {'\0'}; char text[WLED_MAX_SEGNAME_LEN+1] = {'\0'};
if (SEGMENT.name) for (size_t i=0,j=0; i<strlen(SEGMENT.name); i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i]; if (SEGMENT.name) for (size_t i=0,j=0; i<strlen(SEGMENT.name); i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i];
const bool zero = strchr(text, '0') != nullptr;
const int numberOfLetters = strlen(text);
if (!strlen(text)
|| !strncmp_P(text,PSTR("#DATE"),5)
|| !strncmp_P(text,PSTR("#DDMM"),5)
|| !strncmp_P(text,PSTR("#MMDD"),5)
|| !strncmp_P(text,PSTR("#TIME"),5)
|| !strncmp_P(text,PSTR("#HHMM"),5)) { // fallback if empty segment name: display date and time
char sec[5]; char sec[5];
byte AmPmHour = hour(localTime); int AmPmHour = hour(localTime);
boolean isitAM = true; bool isitAM = true;
if (useAMPM) { if (useAMPM) {
if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; } if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; }
if (AmPmHour == 0) { AmPmHour = 12; } if (AmPmHour == 0) { AmPmHour = 12; }
sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
} else {
sprintf_P(sec, PSTR(":%02d"), second(localTime));
} }
if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
else sprintf_P(sec, PSTR(":%02d"), second(localTime));
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d"):PSTR("%d.%d"), day(localTime), month(localTime));
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d"):PSTR("%d/%d"), month(localTime), day(localTime));
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s"):PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d"):PSTR("%d:%02d"), AmPmHour, minute(localTime));
else sprintf_P(text, zero?PSTR("%s %02d, %04d %02d:%02d%s"):PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
}
const int numberOfLetters = strlen(text);
if (SEGENV.step < millis()) { if (!numberOfLetters) { // fallback if empty segment name: display date and time
if ((numberOfLetters * letterWidth) > cols) ++SEGENV.aux0 %= (numberOfLetters * letterWidth) + cols; // offset sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
else SEGENV.aux0 = (cols + (numberOfLetters * letterWidth))/2; } else {
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime));
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime));
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime));
}
const unsigned long now = millis(); // reduce millis() calls
int width = (numberOfLetters * rotLW);
int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-rotLH)/2;
if (width <= cols) {
// scroll vertically (e.g. ^^ Way out ^^) if it fits
int speed = map(SEGMENT.speed, 0, 255, 5000, 1000);
int frac = now % speed + 1;
if (SEGMENT.intensity == 255) {
yoffset = (2 * frac * rows)/speed - rows;
} else if (SEGMENT.intensity == 0) {
yoffset = rows - (2 * frac * rows)/speed;
}
}
if (SEGENV.step < now) {
// calculate start offset
if (width > cols) {
if (SEGMENT.check3) {
if (SEGENV.aux0 == 0) SEGENV.aux0 = width + cols - 1;
else --SEGENV.aux0;
} else ++SEGENV.aux0 %= width + cols;
} else SEGENV.aux0 = (cols + width)/2;
++SEGENV.aux1 &= 0xFF; // color shift ++SEGENV.aux1 &= 0xFF; // color shift
SEGENV.step = millis() + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED); SEGENV.step = now + map(SEGMENT.speed, 0, 255, 250, 50); // shift letters every ~250ms to ~50ms
if (!SEGMENT.check2) {
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++ )
SEGMENT.blendPixelColorXY(x, y, SEGCOLOR(1), 255 - (SEGMENT.custom1>>1));
}
} }
if (!SEGMENT.check2) SEGMENT.fade_out(255 - (SEGMENT.custom1>>4)); // trail
for (int i = 0; i < numberOfLetters; i++) { for (int i = 0; i < numberOfLetters; i++) {
if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen int xoffset = int(cols) - int(SEGENV.aux0) + rotLW*i;
if (xoffset + rotLW < 0) continue; // don't draw characters off-screen
uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0); uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0);
uint32_t col2 = BLACK; uint32_t col2 = BLACK;
if (SEGMENT.check1 && SEGMENT.palette == 0) { if (SEGMENT.check1 && SEGMENT.palette == 0) {
col1 = SEGCOLOR(0); col1 = SEGCOLOR(0);
col2 = SEGCOLOR(2); col2 = SEGCOLOR(2);
} }
SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, col1, col2); SEGMENT.drawCharacter(text[i], xoffset, yoffset, letterWidth, letterHeight, col1, col2, (SEGMENT.custom3+1)>>3);
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,,Gradient,Overlay,0;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0"; static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,Rotate,Gradient,Overlay,Reverse;!,!,Gradient;!;2;ix=128,c1=0,c3=0,rev=0,mi=0,rY=0,mY=0";
//////////////////////////// ////////////////////////////
@ -6021,10 +5991,6 @@ uint16_t mode_2Ddriftrose(void) {
const float CY = (rows-rows%2)/2.f - .5f; const float CY = (rows-rows%2)/2.f - .5f;
const float L = min(cols, rows) / 2.f; const float L = min(cols, rows) / 2.f;
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3)); SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3));
for (size_t i = 1; i < 37; i++) { for (size_t i = 1; i < 37; i++) {
uint32_t x = (CX + (sin_t(radians(i * 10)) * (beatsin8(i, 0, L*2)-L))) * 255.f; uint32_t x = (CX + (sin_t(radians(i * 10)) * (beatsin8(i, 0, L*2)-L))) * 255.f;
@ -6197,8 +6163,6 @@ uint16_t mode_2DSwirl(void) {
float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg??? float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg???
int16_t volumeRaw = *(int16_t*) um_data->u_data[1]; int16_t volumeRaw = *(int16_t*) um_data->u_data[1];
// printUmData();
SEGMENT.addPixelColorXY( i, j, ColorFromPalette(SEGPALETTE, (ms / 11 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 11, 200, 255); SEGMENT.addPixelColorXY( i, j, ColorFromPalette(SEGPALETTE, (ms / 11 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 11, 200, 255);
SEGMENT.addPixelColorXY( j, i, ColorFromPalette(SEGPALETTE, (ms / 13 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 13, 200, 255); SEGMENT.addPixelColorXY( j, i, ColorFromPalette(SEGPALETTE, (ms / 13 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 13, 200, 255);
SEGMENT.addPixelColorXY(ni,nj, ColorFromPalette(SEGPALETTE, (ms / 17 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 17, 200, 255); SEGMENT.addPixelColorXY(ni,nj, ColorFromPalette(SEGPALETTE, (ms / 17 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 17, 200, 255);
@ -6221,10 +6185,6 @@ uint16_t mode_2DWaverly(void) {
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
}
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio // add support for no audio
@ -6272,6 +6232,7 @@ typedef struct Gravity {
// * GRAVCENTER // // * GRAVCENTER //
/////////////////////// ///////////////////////
uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
const uint16_t dataSize = sizeof(gravity); const uint16_t dataSize = sizeof(gravity);
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
@ -6290,7 +6251,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline.
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f;
segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling
float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0); // map to pixels available in current segment float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0f); // map to pixels available in current segment
uint16_t tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. uint16_t tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing.
uint8_t gravity = 8 - SEGMENT.speed/32; uint8_t gravity = 8 - SEGMENT.speed/32;
@ -6320,6 +6281,7 @@ static const char _data_FX_MODE_GRAVCENTER[] PROGMEM = "Gravcenter@Rate of fall,
// * GRAVCENTRIC // // * GRAVCENTRIC //
/////////////////////// ///////////////////////
uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew Tuline. uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
uint16_t dataSize = sizeof(gravity); uint16_t dataSize = sizeof(gravity);
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
@ -6338,10 +6300,10 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew
//SEGMENT.fade_out(240); // twice? really? //SEGMENT.fade_out(240); // twice? really?
SEGMENT.fade_out(253); // 50% SEGMENT.fade_out(253); // 50%
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f;
segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling
float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0); // map to pixels availeable in current segment float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0f); // map to pixels availeable in current segment
int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing.
uint8_t gravity = 8 - SEGMENT.speed/32; uint8_t gravity = 8 - SEGMENT.speed/32;
@ -6371,6 +6333,7 @@ static const char _data_FX_MODE_GRAVCENTRIC[] PROGMEM = "Gravcentric@Rate of fal
// * GRAVIMETER // // * GRAVIMETER //
/////////////////////// ///////////////////////
uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
uint16_t dataSize = sizeof(gravity); uint16_t dataSize = sizeof(gravity);
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
@ -6417,6 +6380,7 @@ static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter@Rate of fall,
// * JUGGLES // // * JUGGLES //
////////////////////// //////////////////////
uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio // add support for no audio
@ -6440,6 +6404,7 @@ static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!;
// * MATRIPIX // // * MATRIPIX //
////////////////////// //////////////////////
uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
um_data_t *um_data; um_data_t *um_data;
@ -6471,6 +6436,7 @@ static const char _data_FX_MODE_MATRIPIX[] PROGMEM = "Matripix@!,Brightness;!,!;
// * MIDNOISE // // * MIDNOISE //
////////////////////// //////////////////////
uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
// Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1. // Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1.
um_data_t *um_data; um_data_t *um_data;
@ -6574,6 +6540,7 @@ static const char _data_FX_MODE_NOISEMETER[] PROGMEM = "Noisemeter@Fade rate,Wid
// * PIXELWAVE // // * PIXELWAVE //
////////////////////// //////////////////////
uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline. uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
@ -6649,6 +6616,7 @@ static const char _data_FX_MODE_PLASMOID[] PROGMEM = "Plasmoid@Phase,# of pixels
/////////////////////// ///////////////////////
// Andrew's crappy peak detector. If I were 40+ years younger, I'd learn signal processing. // Andrew's crappy peak detector. If I were 40+ years younger, I'd learn signal processing.
uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
uint16_t size = 0; uint16_t size = 0;
uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254); uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254);
@ -6692,6 +6660,7 @@ static const char _data_FX_MODE_PUDDLEPEAK[] PROGMEM = "Puddlepeak@Fade rate,Pud
// * PUDDLES // // * PUDDLES //
////////////////////// //////////////////////
uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline. uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
uint16_t size = 0; uint16_t size = 0;
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254); uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254);
uint16_t pos = random16(SEGLEN); // Set a random starting position. uint16_t pos = random16(SEGLEN); // Set a random starting position.
@ -6723,6 +6692,7 @@ static const char _data_FX_MODE_PUDDLES[] PROGMEM = "Puddles@Fade rate,Puddle si
// * PIXELS // // * PIXELS //
////////////////////// //////////////////////
uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline. uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
if (!SEGENV.allocateData(32*sizeof(uint8_t))) return mode_static(); //allocation failed if (!SEGENV.allocateData(32*sizeof(uint8_t))) return mode_static(); //allocation failed
uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low. uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low.
@ -6756,6 +6726,7 @@ static const char _data_FX_MODE_PIXELS[] PROGMEM = "Pixels@Fade rate,# of pixels
// ** Blurz // // ** Blurz //
////////////////////// //////////////////////
uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
um_data_t *um_data; um_data_t *um_data;
@ -6776,7 +6747,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
SEGENV.step += FRAMETIME; SEGENV.step += FRAMETIME;
if (SEGENV.step > SPEED_FORMULA_L) { if (SEGENV.step > SPEED_FORMULA_L) {
uint16_t segLoc = random16(SEGLEN); uint16_t segLoc = random16(SEGLEN);
SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/(SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16])); SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16]));
++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16 ++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16
SEGENV.step = 1; SEGENV.step = 1;
@ -6792,6 +6763,7 @@ static const char _data_FX_MODE_BLURZ[] PROGMEM = "Blurz@Fade rate,Blur;!,Color
// ** DJLight // // ** DJLight //
///////////////////////// /////////////////////////
uint16_t mode_DJLight(void) { // Written by ??? Adapted by Will Tatam. uint16_t mode_DJLight(void) { // Written by ??? Adapted by Will Tatam.
if (SEGLEN == 1) return mode_static();
const int mid = SEGLEN / 2; const int mid = SEGLEN / 2;
um_data_t *um_data; um_data_t *um_data;
@ -6825,6 +6797,7 @@ static const char _data_FX_MODE_DJLIGHT[] PROGMEM = "DJ Light@Speed;;;1f;m12=2,s
// ** Freqmap // // ** Freqmap //
//////////////////// ////////////////////
uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. Would be better if a higher framerate. uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. Would be better if a higher framerate.
if (SEGLEN == 1) return mode_static();
// Start frequency = 60 Hz and log10(60) = 1.78 // Start frequency = 60 Hz and log10(60) = 1.78
// End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10 // End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10
@ -6861,6 +6834,7 @@ static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting
// ** Freqmatrix // // ** Freqmatrix //
/////////////////////// ///////////////////////
uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung. uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung.
if (SEGLEN == 1) return mode_static();
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio // add support for no audio
@ -6926,24 +6900,27 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
} }
float FFT_MajorPeak = *(float*)um_data->u_data[4]; float FFT_MajorPeak = *(float*)um_data->u_data[4];
float my_magnitude = *(float*)um_data->u_data[5] / 16.0f; float my_magnitude = *(float*)um_data->u_data[5] / 16.0f;
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) if (FFT_MajorPeak < 1) FFT_MajorPeak = 1.0f; // log10(0) is "forbidden" (throws exception)
uint16_t fadeRate = 2*SEGMENT.speed - SEGMENT.speed*SEGMENT.speed/255; // Get to 255 as quick as you can. // this code translates to speed * (2 - speed/255) which is a) speed*2 or b) speed (when speed is 255)
// and since fade_out() can only take 0-255 it will behave incorrectly when speed > 127
//uint16_t fadeRate = 2*SEGMENT.speed - SEGMENT.speed*SEGMENT.speed/255; // Get to 255 as quick as you can.
uint16_t fadeRate = SEGMENT.speed*SEGMENT.speed; // Get to 255 as quick as you can.
fadeRate = map(fadeRate, 0, 65535, 1, 255);
if (SEGENV.call == 0) SEGMENT.fill(BLACK);
int fadeoutDelay = (256 - SEGMENT.speed) / 64; int fadeoutDelay = (256 - SEGMENT.speed) / 64;
if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(fadeRate); if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(fadeRate);
for (int i=0; i < SEGMENT.intensity/32+1; i++) {
uint16_t locn = random16(0,SEGLEN);
uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index.
if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow
for (int i=0; i < SEGMENT.intensity/32+1; i++) {
uint16_t locn = random16(0,SEGLEN);
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude));
} }
return FRAMETIME; return FRAMETIME;
} // mode_freqpixels() } // mode_freqpixels()
static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Starting color and # of pixels;;;1f;m12=0,si=0"; // Pixels, Beatsin static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Starting color and # of pixels;!,!,;!;1f;m12=0,si=0"; // Pixels, Beatsin
////////////////////// //////////////////////
@ -6962,6 +6939,7 @@ static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Sta
// As a compromise between speed and accuracy we are currently sampling with 10240Hz, from which we can then determine with a 512bin FFT our max frequency is 5120Hz. // As a compromise between speed and accuracy we are currently sampling with 10240Hz, from which we can then determine with a 512bin FFT our max frequency is 5120Hz.
// Depending on the music stream you have you might find it useful to change the frequency mapping. // Depending on the music stream you have you might find it useful to change the frequency mapping.
uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschung. uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschung.
if (SEGLEN == 1) return mode_static();
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio // add support for no audio
@ -7018,7 +6996,7 @@ static const char _data_FX_MODE_FREQWAVE[] PROGMEM = "Freqwave@Speed,Sound effec
// ** Gravfreq // // ** Gravfreq //
/////////////////////// ///////////////////////
uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline.
if (SEGLEN == 1) return mode_static();
uint16_t dataSize = sizeof(gravity); uint16_t dataSize = sizeof(gravity);
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
Gravity* gravcen = reinterpret_cast<Gravity*>(SEGENV.data); Gravity* gravcen = reinterpret_cast<Gravity*>(SEGENV.data);
@ -7035,9 +7013,9 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline.
SEGMENT.fade_out(250); SEGMENT.fade_out(250);
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f;
segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling
float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0,32, 0, (float)SEGLEN/2.0); // map to pixels availeable in current segment float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0,32, 0, (float)SEGLEN/2.0f); // map to pixels availeable in current segment
int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing. int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing.
uint8_t gravity = 8 - SEGMENT.speed/32; uint8_t gravity = 8 - SEGMENT.speed/32;
@ -7070,6 +7048,7 @@ static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sens
// ** Noisemove // // ** Noisemove //
////////////////////// //////////////////////
uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuline uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuline
if (SEGLEN == 1) return mode_static();
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio // add support for no audio
@ -7077,8 +7056,6 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli
} }
uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
if (SEGENV.call == 0) SEGMENT.fill(BLACK);
//SEGMENT.fade_out(224); // Just in case something doesn't get faded.
int fadeoutDelay = (256 - SEGMENT.speed) / 96; int fadeoutDelay = (256 - SEGMENT.speed) / 96;
if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(4+ SEGMENT.speed/4); if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(4+ SEGMENT.speed/4);
@ -7098,6 +7075,7 @@ static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Speed of perlin
// ** Rocktaves // // ** Rocktaves //
////////////////////// //////////////////////
uint16_t mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline uint16_t mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline
if (SEGLEN == 1) return mode_static();
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio // add support for no audio
@ -7106,7 +7084,6 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac
float FFT_MajorPeak = *(float*) um_data->u_data[4]; float FFT_MajorPeak = *(float*) um_data->u_data[4];
float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; float my_magnitude = *(float*) um_data->u_data[5] / 16.0f;
if (SEGENV.call == 0) SEGMENT.fill(BLACK);
SEGMENT.fadeToBlackBy(16); // Just in case something doesn't get faded. SEGMENT.fadeToBlackBy(16); // Just in case something doesn't get faded.
float frTemp = FFT_MajorPeak; float frTemp = FFT_MajorPeak;
@ -7122,7 +7099,7 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac
frTemp = frTemp/2; frTemp = frTemp/2;
} }
frTemp -=132; // This should give us a base musical note of C3 frTemp -= 132.0f; // This should give us a base musical note of C3
frTemp = fabsf(frTemp * 2.1f); // Fudge factors to compress octave range starting at 0 and going to 255; frTemp = fabsf(frTemp * 2.1f); // Fudge factors to compress octave range starting at 0 and going to 255;
uint16_t i = map(beatsin8(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); uint16_t i = map(beatsin8(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1);
@ -7139,7 +7116,7 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;1f;m12=1
/////////////////////// ///////////////////////
// Combines peak detection with FFT_MajorPeak and FFT_Magnitude. // Combines peak detection with FFT_MajorPeak and FFT_Magnitude.
uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline
if (SEGENV.call == 0) SEGMENT.fill(BLACK); if (SEGLEN == 1) return mode_static();
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
@ -7214,7 +7191,6 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma.
rippleTime = true; rippleTime = true;
} }
if (SEGENV.call == 0) SEGMENT.fill(BLACK);
int fadeoutDelay = (256 - SEGMENT.speed) / 64; int fadeoutDelay = (256 - SEGMENT.speed) / 64;
if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed); if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed);
@ -7516,6 +7492,7 @@ uint16_t mode_2Dsoap() {
int amplitude; int amplitude;
int8_t shiftX = 0; //(SEGMENT.custom1 - 128) / 4; int8_t shiftX = 0; //(SEGMENT.custom1 - 128) / 4;
int8_t shiftY = 0; //(SEGMENT.custom2 - 128) / 4; int8_t shiftY = 0; //(SEGMENT.custom2 - 128) / 4;
CRGB ledsbuff[MAX(cols,rows)];
amplitude = (cols >= 16) ? (cols-8)/8 : 1; amplitude = (cols >= 16) ? (cols-8)/8 : 1;
for (int y = 0; y < rows; y++) { for (int y = 0; y < rows; y++) {
@ -7536,9 +7513,9 @@ uint16_t mode_2Dsoap() {
CRGB PixelB = CRGB::Black; CRGB PixelB = CRGB::Black;
if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y); if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y);
else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zF),y)]*3); else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zF),y)]*3);
CRGB pix = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); ledsbuff[x] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
SEGMENT.setPixelColorXY(x, y, pix);
} }
for (int x = 0; x < cols; x++) SEGMENT.setPixelColorXY(x, y, ledsbuff[x]);
} }
amplitude = (rows >= 16) ? (rows-8)/8 : 1; amplitude = (rows >= 16) ? (rows-8)/8 : 1;
@ -7560,9 +7537,9 @@ uint16_t mode_2Dsoap() {
CRGB PixelB = CRGB::Black; CRGB PixelB = CRGB::Black;
if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF); if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF);
else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zF))]*3); else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zF))]*3);
CRGB pix = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); ledsbuff[y] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
SEGMENT.setPixelColorXY(x, y, pix);
} }
for (int y = 0; y < rows; y++) SEGMENT.setPixelColorXY(x, y, ledsbuff[y]);
} }
return FRAMETIME; return FRAMETIME;

View File

@ -381,6 +381,26 @@ typedef struct Segment {
byte *data; // effect data pointer byte *data; // effect data pointer
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions) static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
typedef struct TemporarySegmentData {
uint16_t _optionsT;
uint32_t _colorT[NUM_COLORS];
uint8_t _speedT;
uint8_t _intensityT;
uint8_t _custom1T, _custom2T; // custom FX parameters/sliders
struct {
uint8_t _custom3T : 5; // reduced range slider (0-31)
bool _check1T : 1; // checkmark 1
bool _check2T : 1; // checkmark 2
bool _check3T : 1; // checkmark 3
};
uint16_t _aux0T;
uint16_t _aux1T;
uint32_t _stepT;
uint32_t _callT;
uint8_t *_dataT;
uint16_t _dataLenT;
} tmpsegd_t;
private: private:
union { union {
uint8_t _capabilities; uint8_t _capabilities;
@ -395,39 +415,34 @@ typedef struct Segment {
uint16_t _dataLen; uint16_t _dataLen;
static uint16_t _usedSegmentData; static uint16_t _usedSegmentData;
// perhaps this should be per segment, not static
static CRGBPalette16 _randomPalette; // actual random palette
static CRGBPalette16 _newRandomPalette; // target random palette
static unsigned long _lastPaletteChange; // last random palette change time in millis()
#ifndef WLED_DISABLE_MODE_BLEND
static bool _modeBlend; // mode/effect blending semaphore
#endif
// transition data, valid only if transitional==true, holds values during transition (72 bytes) // transition data, valid only if transitional==true, holds values during transition (72 bytes)
struct Transition { struct Transition {
#ifndef WLED_DISABLE_MODE_BLEND
tmpsegd_t _segT; // previous segment environment
uint8_t _modeT; // previous mode/effect
#else
uint32_t _colorT[NUM_COLORS]; uint32_t _colorT[NUM_COLORS];
#endif
uint8_t _briT; // temporary brightness uint8_t _briT; // temporary brightness
uint8_t _cctT; // temporary CCT uint8_t _cctT; // temporary CCT
CRGBPalette16 _palT; // temporary palette CRGBPalette16 _palT; // temporary palette
uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 belnds possible) uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 belnds possible)
uint8_t _modeP; // previous mode/effect
//uint16_t _aux0, _aux1; // previous mode/effect runtime data
//uint32_t _step, _call; // previous mode/effect runtime data
//byte *_data; // previous mode/effect runtime data
unsigned long _start; // must accommodate millis() unsigned long _start; // must accommodate millis()
uint16_t _dur; uint16_t _dur;
Transition(uint16_t dur=750) Transition(uint16_t dur=750)
: _briT(255) : _palT(CRGBPalette16(CRGB::Black))
, _cctT(127)
, _palT(CRGBPalette16(CRGB::Black))
, _prevPaletteBlends(0) , _prevPaletteBlends(0)
, _modeP(FX_MODE_STATIC)
, _start(millis()) , _start(millis())
, _dur(dur) , _dur(dur)
{} {}
Transition(uint16_t d, uint8_t b, uint8_t c, const uint32_t *o)
: _briT(b)
, _cctT(c)
, _palT(CRGBPalette16(CRGB::Black))
, _prevPaletteBlends(0)
, _modeP(FX_MODE_STATIC)
, _start(millis())
, _dur(d)
{
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = o[i];
}
} *_t; } *_t;
public: public:
@ -466,6 +481,9 @@ typedef struct Segment {
_t(nullptr) _t(nullptr)
{ {
//refreshLightCapabilities(); //refreshLightCapabilities();
#ifdef WLED_DEBUG
//Serial.printf("-- Creating segment: %p\n", this);
#endif
} }
Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) : Segment(sStartX, sStopX) { Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) : Segment(sStartX, sStopX) {
@ -477,14 +495,14 @@ typedef struct Segment {
Segment(Segment &&orig) noexcept; // move constructor Segment(Segment &&orig) noexcept; // move constructor
~Segment() { ~Segment() {
//#ifdef WLED_DEBUG #ifdef WLED_DEBUG
//Serial.print(F("Destroying segment:")); //Serial.printf("-- Destroying segment: %p\n", this);
//if (name) Serial.printf(" %s (%p)", name, name); //if (name) Serial.printf(" %s (%p)", name, name);
//if (data) Serial.printf(" %d (%p)", (int)_dataLen, data); //if (data) Serial.printf(" %d (%p)", (int)_dataLen, data);
//Serial.println(); //Serial.println();
//#endif #endif
if (name) { delete[] name; name = nullptr; } if (name) { delete[] name; name = nullptr; }
if (_t) { transitional = false; delete _t; _t = nullptr; } stopTransition();
deallocateData(); deallocateData();
} }
@ -510,6 +528,10 @@ typedef struct Segment {
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; } static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
static void addUsedSegmentData(int len) { _usedSegmentData += len; } static void addUsedSegmentData(int len) { _usedSegmentData += len; }
#ifndef WLED_DISABLE_MODE_BLEND
static void modeBlend(bool blend) { _modeBlend = blend; }
#endif
static void handleRandomPalette();
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t segId = 255); void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t segId = 255);
bool setColor(uint8_t slot, uint32_t c); //returns true if changed bool setColor(uint8_t slot, uint32_t c); //returns true if changed
@ -536,7 +558,12 @@ typedef struct Segment {
// transition functions // transition functions
void startTransition(uint16_t dur); // transition has to start before actual segment values change void startTransition(uint16_t dur); // transition has to start before actual segment values change
void stopTransition(void);
void handleTransition(void); void handleTransition(void);
#ifndef WLED_DISABLE_MODE_BLEND
void swapSegenv(tmpsegd_t &tmpSegD);
void restoreSegenv(tmpsegd_t &tmpSegD);
#endif
uint16_t progress(void); //transition progression between 0-65535 uint16_t progress(void); //transition progression between 0-65535
uint8_t currentBri(uint8_t briNew, bool useCct = false); uint8_t currentBri(uint8_t briNew, bool useCct = false);
uint8_t currentMode(uint8_t modeNew); uint8_t currentMode(uint8_t modeNew);
@ -598,9 +625,9 @@ typedef struct Segment {
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0); void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, uint8_t rotate = 0);
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, uint8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline
void wu_pixel(uint32_t x, uint32_t y, CRGB c); void wu_pixel(uint32_t x, uint32_t y, CRGB c);
void blur1d(fract8 blur_amount); // blur all rows in 1 dimension void blur1d(fract8 blur_amount); // blur all rows in 1 dimension
void blur2d(fract8 blur_amount) { blur(blur_amount); } void blur2d(fract8 blur_amount) { blur(blur_amount); }

View File

@ -216,23 +216,29 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
y *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
uint32_t tmpCol = col;
for (int j = 0; j < grouping; j++) { // groupping vertically for (int j = 0; j < grouping; j++) { // groupping vertically
for (int g = 0; g < grouping; g++) { // groupping horizontally for (int g = 0; g < grouping; g++) { // groupping horizontally
uint16_t xX = (x+g), yY = (y+j); uint16_t xX = (x+g), yY = (y+j);
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
strip.setPixelColorXY(start + xX, startY + yY, col); #ifndef WLED_DISABLE_MODE_BLEND
// if blending modes, blend with underlying pixel
if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true);
#endif
strip.setPixelColorXY(start + xX, startY + yY, tmpCol);
if (mirror) { //set the corresponding horizontally mirrored pixel if (mirror) { //set the corresponding horizontally mirrored pixel
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
} }
if (mirror_y) { //set the corresponding vertically mirrored pixel if (mirror_y) { //set the corresponding vertically mirrored pixel
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
} }
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, col); strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, tmpCol);
} }
} }
} }
@ -565,7 +571,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
// draws a raster font character on canvas // draws a raster font character on canvas
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM // only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2) { void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, uint8_t rotate) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
chr -= 32; // align with font table entries chr -= 32; // align with font table entries
@ -578,9 +584,6 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
//if (w<5 || w>6 || h!=8) return; //if (w<5 || w>6 || h!=8) return;
for (int i = 0; i<h; i++) { // character height for (int i = 0; i<h; i++) { // character height
int16_t y0 = y + i;
if (y0 < 0) continue; // drawing off-screen
if (y0 >= rows) break; // drawing off-screen
uint8_t bits = 0; uint8_t bits = 0;
switch (font) { switch (font) {
case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]); break; // 5x8 font case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]); break; // 5x8 font
@ -592,8 +595,15 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
} }
col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND); col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
for (int j = 0; j<w; j++) { // character width for (int j = 0; j<w; j++) { // character width
int16_t x0 = x + (w-1) - j; int x0, y0;
if ((x0 >= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen switch (rotate) {
case 3: x0 = x + (h-1) - i; y0 = y + (w-1) - j; break;
case 2: x0 = x + j; y0 = y + (h-1) - i; break;
case 1: x0 = x + i; y0 = y + j; break;
default: x0 = x + (w-1) - j; y0 = y + i; break;
}
if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen
if (((bits>>(j+(8-w))) & 0x01)) { // bit set
setPixelColorXY(x0, y0, col); setPixelColorXY(x0, y0, col);
} }
} }

View File

@ -77,9 +77,17 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
uint16_t Segment::maxHeight = 1; uint16_t Segment::maxHeight = 1;
CRGBPalette16 Segment::_randomPalette = CRGBPalette16(DEFAULT_COLOR);
CRGBPalette16 Segment::_newRandomPalette = CRGBPalette16(DEFAULT_COLOR);
unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment
#ifndef WLED_DISABLE_MODE_BLEND
bool Segment::_modeBlend = false;
#endif
// copy constructor // copy constructor
Segment::Segment(const Segment &orig) { Segment::Segment(const Segment &orig) {
//DEBUG_PRINTLN(F("-- Copy segment constructor --")); //DEBUG_PRINTF("-- Copy segment constructor: %p -> %p\n", &orig, this);
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
transitional = false; // copied segment cannot be in transition transitional = false; // copied segment cannot be in transition
name = nullptr; name = nullptr;
@ -88,12 +96,12 @@ Segment::Segment(const Segment &orig) {
_t = nullptr; _t = nullptr;
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } if (orig.data) { if (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); } //if (orig._t) { _t = new Transition(orig._t->_dur); }
} }
// move constructor // move constructor
Segment::Segment(Segment &&orig) noexcept { Segment::Segment(Segment &&orig) noexcept {
//DEBUG_PRINTLN(F("-- Move segment constructor --")); //DEBUG_PRINTF("-- Move segment constructor: %p -> %p\n", &orig, this);
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.transitional = false; // old segment cannot be in transition any more orig.transitional = false; // old segment cannot be in transition any more
orig.name = nullptr; orig.name = nullptr;
@ -104,12 +112,17 @@ Segment::Segment(Segment &&orig) noexcept {
// copy assignment // copy assignment
Segment& Segment::operator= (const Segment &orig) { Segment& Segment::operator= (const Segment &orig) {
//DEBUG_PRINTLN(F("-- Copying segment --")); //DEBUG_PRINTF("-- Copying segment: %p -> %p\n", &orig, this);
if (this != &orig) { if (this != &orig) {
// clean destination // clean destination
transitional = false; // copied segment cannot be in transition transitional = false; // copied segment cannot be in transition
if (name) delete[] name; if (name) delete[] name;
if (_t) delete _t; if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT) free(_t->_segT._dataT);
#endif
delete _t;
}
deallocateData(); deallocateData();
// copy source // copy source
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
@ -129,12 +142,18 @@ Segment& Segment::operator= (const Segment &orig) {
// move assignment // move assignment
Segment& Segment::operator= (Segment &&orig) noexcept { Segment& Segment::operator= (Segment &&orig) noexcept {
//DEBUG_PRINTLN(F("-- Moving segment --")); //DEBUG_PRINTF("-- Moving segment: %p -> %p\n", &orig, this);
if (this != &orig) { if (this != &orig) {
transitional = false; // just temporary transitional = false; // just temporary
if (name) { delete[] name; name = nullptr; } // free old name if (name) { delete[] name; name = nullptr; } // free old name
deallocateData(); // free old runtime data deallocateData(); // free old runtime data
if (_t) { delete _t; _t = nullptr; } if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT) free(_t->_segT._dataT);
#endif
delete _t;
_t = nullptr;
}
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.transitional = false; // old segment cannot be in transition orig.transitional = false; // old segment cannot be in transition
orig.name = nullptr; orig.name = nullptr;
@ -147,12 +166,18 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
bool Segment::allocateData(size_t len) { bool Segment::allocateData(size_t len) {
if (data && _dataLen == len) return true; //already allocated if (data && _dataLen == len) return true; //already allocated
//DEBUG_PRINTF("-- Allocating data (%d): %p\n", len, this);
deallocateData(); deallocateData();
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) {
// not enough memory
DEBUG_PRINTF("!!! Effect RAM depleted: %d/%d !!!\n", len, Segment::getUsedSegmentData());
return false;
}
// do not use SPI RAM on ESP32 since it is slow // do not use SPI RAM on ESP32 since it is slow
data = (byte*) malloc(len); data = (byte*) malloc(len);
if (!data) return false; //allocation failed if (!data) { DEBUG_PRINTLN(F("!!! Allocation failed. !!!")); return false; } //allocation failed
Segment::addUsedSegmentData(len); Segment::addUsedSegmentData(len);
//DEBUG_PRINTF("--- Allocated data (%p): %d/%d -> %p\n", this, len, Segment::getUsedSegmentData(), data);
_dataLen = len; _dataLen = len;
memset(data, 0, len); memset(data, 0, len);
return true; return true;
@ -160,9 +185,11 @@ bool Segment::allocateData(size_t len) {
void Segment::deallocateData() { void Segment::deallocateData() {
if (!data) return; if (!data) return;
//DEBUG_PRINTF("--- Released data (%p): %d/%d -> %p\n", this, _dataLen, Segment::getUsedSegmentData(), data);
free(data); free(data);
data = nullptr; data = nullptr;
Segment::addUsedSegmentData(-_dataLen); // WARNING it looks like we have a memory leak somewhere
Segment::addUsedSegmentData(_dataLen <= Segment::getUsedSegmentData() ? -_dataLen : -Segment::getUsedSegmentData());
_dataLen = 0; _dataLen = 0;
} }
@ -175,17 +202,13 @@ void Segment::deallocateData() {
*/ */
void Segment::resetIfRequired() { void Segment::resetIfRequired() {
if (!reset) return; if (!reset) return;
//DEBUG_PRINTF("-- Segment reset: %p\n", this);
deallocateData(); deallocateData();
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
reset = false; reset = false;
} }
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment
static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR);
static CRGBPalette16 prevRandomPalette = CRGBPalette16(CRGB(BLACK));
byte tcp[72];
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0;
//default palette. Differs depending on effect //default palette. Differs depending on effect
@ -206,27 +229,18 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
case 0: //default palette. Exceptions for specific effects above case 0: //default palette. Exceptions for specific effects above
targetPalette = PartyColors_p; break; targetPalette = PartyColors_p; break;
case 1: {//periodically replace palette with a random one. Transition palette change in 500ms case 1: {//periodically replace palette with a random one. Transition palette change in 500ms
uint32_t timeSinceLastChange = millis() - _lastPaletteChange; unsigned long timeSinceLastChange = millis() - _lastPaletteChange;
if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { if (timeSinceLastChange > randomPaletteChangeTime * 1000U) {
prevRandomPalette = randomPalette; _randomPalette = _newRandomPalette;
randomPalette = CRGBPalette16( _newRandomPalette = CRGBPalette16(
CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255))); CHSV(random8(), random8(160, 255), random8(128, 255)));
_lastPaletteChange = millis(); _lastPaletteChange = millis();
timeSinceLastChange = 0; handleRandomPalette(); // do a 1st pass of blend
}
if (timeSinceLastChange <= 250) {
targetPalette = prevRandomPalette;
// there needs to be 255 palette blends (48) for full blend but that is too resource intensive
// so 128 is a compromise (we need to perform full blend of the two palettes as each segment can have random
// palette selected but only 2 static palettes are used)
size_t noOfBlends = ((128U * timeSinceLastChange) / 250U);
for (size_t i=0; i<noOfBlends; i++) nblendPaletteTowardPalette(targetPalette, randomPalette, 48);
} else {
targetPalette = randomPalette;
} }
targetPalette = _randomPalette;
break;} break;}
case 2: {//primary color only case 2: {//primary color only
CRGB prim = gamma32(colors[0]); CRGB prim = gamma32(colors[0]);
@ -268,6 +282,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
if (pal>245) { if (pal>245) {
targetPalette = strip.customPalettes[255-pal]; // we checked bounds above targetPalette = strip.customPalettes[255-pal]; // we checked bounds above
} else { } else {
byte tcp[72];
memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[pal-13])), 72); memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[pal-13])), 72);
targetPalette.loadDynamicGradientPalette(tcp); targetPalette.loadDynamicGradientPalette(tcp);
} }
@ -278,11 +293,8 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
void Segment::startTransition(uint16_t dur) { void Segment::startTransition(uint16_t dur) {
if (!dur) { if (!dur) {
transitional = false; if (_t) _t->_dur = dur; // this will stop transition in next handleTransisiton()
if (_t) { else transitional = false;
delete _t;
_t = nullptr;
}
return; return;
} }
if (transitional && _t) return; // already in transition no need to store anything if (transitional && _t) return; // already in transition no need to store anything
@ -291,44 +303,165 @@ void Segment::startTransition(uint16_t dur) {
_t = new Transition(dur); // no previous transition running _t = new Transition(dur); // no previous transition running
if (!_t) return; // failed to allocate data if (!_t) return; // failed to allocate data
//DEBUG_PRINTF("-- Started transition: %p\n", this);
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette); CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
_t->_palT = _palT;
_t->_briT = on ? opacity : 0; _t->_briT = on ? opacity : 0;
_t->_cctT = cct; _t->_cctT = cct;
_t->_palT = _palT; #ifndef WLED_DISABLE_MODE_BLEND
_t->_modeP = mode; swapSegenv(_t->_segT);
_t->_modeT = mode;
_t->_segT._optionsT |= 0b0000000001000000; // mark old segment transitional
_t->_segT._dataLenT = 0;
_t->_segT._dataT = nullptr;
if (_dataLen > 0 && data) {
_t->_segT._dataT = (byte *)malloc(_dataLen);
if (_t->_segT._dataT) {
//DEBUG_PRINTF("-- Allocated duplicate data (%d): %p\n", _dataLen, _t->_segT._dataT);
memcpy(_t->_segT._dataT, data, _dataLen);
_t->_segT._dataLenT = _dataLen;
}
}
#else
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i]; for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
#endif
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true); transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
} }
void Segment::stopTransition() {
if (!transitional) return;
transitional = false; // finish transitioning segment
//DEBUG_PRINTF("-- Stopping transition: %p\n", this);
if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT && _t->_segT._dataLenT > 0) {
//DEBUG_PRINTF("-- Released duplicate data (%d): %p\n", _t->_segT._dataLenT, _t->_segT._dataT);
free(_t->_segT._dataT);
_t->_segT._dataT = nullptr;
}
#endif
delete _t;
_t = nullptr;
}
}
void Segment::handleTransition() {
if (!transitional) return;
uint16_t _progress = progress();
if (_progress == 0xFFFFU) stopTransition();
}
// transition progression between 0-65535 // transition progression between 0-65535
uint16_t Segment::progress() { uint16_t Segment::progress() {
if (!transitional || !_t) return 0xFFFFU; if (transitional && _t) {
unsigned long timeNow = millis(); unsigned long timeNow = millis();
if (timeNow - _t->_start > _t->_dur || _t->_dur == 0) return 0xFFFFU; if (_t->_dur > 0 && timeNow - _t->_start < _t->_dur) return (timeNow - _t->_start) * 0xFFFFU / _t->_dur;
return (timeNow - _t->_start) * 0xFFFFU / _t->_dur; }
return 0xFFFFU;
} }
#ifndef WLED_DISABLE_MODE_BLEND
void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
if (!_t) return;
//DEBUG_PRINTF("-- Saving temp seg: %p (%p)\n", this, tmpSeg);
tmpSeg._optionsT = options;
for (size_t i=0; i<NUM_COLORS; i++) tmpSeg._colorT[i] = colors[i];
tmpSeg._speedT = speed;
tmpSeg._intensityT = intensity;
tmpSeg._custom1T = custom1;
tmpSeg._custom2T = custom2;
tmpSeg._custom3T = custom3;
tmpSeg._check1T = check1;
tmpSeg._check2T = check2;
tmpSeg._check3T = check3;
tmpSeg._aux0T = aux0;
tmpSeg._aux1T = aux1;
tmpSeg._stepT = step;
tmpSeg._callT = call;
tmpSeg._dataT = data;
tmpSeg._dataLenT = _dataLen;
if (&tmpSeg != &(_t->_segT)) {
// swap SEGENV with transitional data
options = _t->_segT._optionsT;
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = _t->_segT._colorT[i];
speed = _t->_segT._speedT;
intensity = _t->_segT._intensityT;
custom1 = _t->_segT._custom1T;
custom2 = _t->_segT._custom2T;
custom3 = _t->_segT._custom3T;
check1 = _t->_segT._check1T;
check2 = _t->_segT._check2T;
check3 = _t->_segT._check3T;
aux0 = _t->_segT._aux0T;
aux1 = _t->_segT._aux1T;
step = _t->_segT._stepT;
call = _t->_segT._callT;
data = _t->_segT._dataT;
_dataLen = _t->_segT._dataLenT;
}
//DEBUG_PRINTF("-- temp seg data: %p (%d,%p)\n", this, _dataLen, data);
}
void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
//DEBUG_PRINTF("-- Restoring temp seg: %p (%p)\n", this, tmpSeg);
if (_t && &(_t->_segT) != &tmpSeg) {
// update possibly changed variables to keep old effect running correctly
_t->_segT._aux0T = aux0;
_t->_segT._aux1T = aux1;
_t->_segT._stepT = step;
_t->_segT._callT = call;
//if (_t->_segT._dataT != data) DEBUG_PRINTF("--- data re-allocated: (%p) %p -> %p\n", this, _t->_segT._dataT, data);
_t->_segT._dataT = data; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
_t->_segT._dataLenT = _dataLen; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
}
options = tmpSeg._optionsT;
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = tmpSeg._colorT[i];
speed = tmpSeg._speedT;
intensity = tmpSeg._intensityT;
custom1 = tmpSeg._custom1T;
custom2 = tmpSeg._custom2T;
custom3 = tmpSeg._custom3T;
check1 = tmpSeg._check1T;
check2 = tmpSeg._check2T;
check3 = tmpSeg._check3T;
aux0 = tmpSeg._aux0T;
aux1 = tmpSeg._aux1T;
step = tmpSeg._stepT;
call = tmpSeg._callT;
data = tmpSeg._dataT;
_dataLen = tmpSeg._dataLenT;
//DEBUG_PRINTF("-- temp seg data: %p (%d,%p)\n", this, _dataLen, data);
}
#endif
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) { uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
uint32_t prog = progress(); uint32_t prog = progress();
if (transitional && _t && prog < 0xFFFFU) { if (prog < 0xFFFFU) {
if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16; if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16;
else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16; else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16;
} else {
return briNew;
} }
return briNew;
} }
uint8_t Segment::currentMode(uint8_t newMode) { uint8_t Segment::currentMode(uint8_t newMode) {
return (progress()>32767U) ? newMode : _t->_modeP; // change effect in the middle of transition #ifndef WLED_DISABLE_MODE_BLEND
uint16_t prog = progress(); // implicit check for transitional & _t in progress()
if (prog < 0xFFFFU) return _t->_modeT;
#endif
return newMode;
} }
uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) { uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) {
#ifndef WLED_DISABLE_MODE_BLEND
return transitional && _t ? color_blend(_t->_segT._colorT[slot], colorNew, progress(), true) : colorNew;
#else
return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew; return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew;
#endif
} }
CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) { CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
loadPalette(targetPalette, pal); loadPalette(targetPalette, pal);
if (transitional && _t && progress() < 0xFFFFU) { if (progress() < 0xFFFFU) {
// blend palettes // blend palettes
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
// minimum blend time is 100ms maximum is 65535ms // minimum blend time is 100ms maximum is 65535ms
@ -340,17 +473,11 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal
return targetPalette; return targetPalette;
} }
void Segment::handleTransition() { // relies on WS2812FX::service() to call it max every 8ms or more (MIN_SHOW_DELAY)
if (!transitional) return; void Segment::handleRandomPalette() {
uint16_t _progress = progress(); // just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette)
if (_progress == 0xFFFFU) transitional = false; // finish transitioning segment // this will slowly blend _newRandomPalette into _randomPalette every 15ms or 8ms (depending on MIN_SHOW_DELAY)
if (_t) { // thanks to @nXm AKA https://github.com/NMeirer nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
if (_progress >= 32767U && _t->_modeP != mode) markForReset();
if (_progress == 0xFFFFU) {
delete _t;
_t = nullptr;
}
}
} }
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function // segId is given when called from network callback, changes are queued if that segment is currently in its effect function
@ -428,6 +555,7 @@ void Segment::setCCT(uint16_t k) {
void Segment::setOpacity(uint8_t o) { void Segment::setOpacity(uint8_t o) {
if (opacity == o) return; if (opacity == o) return;
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
DEBUG_PRINT(F("-- Setting opacity: ")); DEBUG_PRINTLN(o);
opacity = o; opacity = o;
stateChanged = true; // send UDP/WS broadcast stateChanged = true; // send UDP/WS broadcast
} }
@ -446,7 +574,6 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
if (fx != mode) { if (fx != mode) {
if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions
mode = fx; mode = fx;
// load default values from effect string // load default values from effect string
if (loadDefaults) { if (loadDefaults) {
int16_t sOpt; int16_t sOpt;
@ -466,6 +593,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0); sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
} }
markForReset();
stateChanged = true; // send UDP/WS broadcast stateChanged = true; // send UDP/WS broadcast
} }
} }
@ -626,6 +754,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
} }
i += start; // starting pixel in a group i += start; // starting pixel in a group
uint32_t tmpCol = col;
// set all the pixels in the group // set all the pixels in the group
for (int j = 0; j < grouping; j++) { for (int j = 0; j < grouping; j++) {
uint16_t indexSet = i + ((reverse) ? -j : j); uint16_t indexSet = i + ((reverse) ? -j : j);
@ -634,11 +763,17 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
uint16_t indexMir = stop - indexSet + start - 1; uint16_t indexMir = stop - indexSet + start - 1;
indexMir += offset; // offset/phase indexMir += offset; // offset/phase
if (indexMir >= stop) indexMir -= len; // wrap if (indexMir >= stop) indexMir -= len; // wrap
strip.setPixelColor(indexMir, col); #ifndef WLED_DISABLE_MODE_BLEND
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true);
#endif
strip.setPixelColor(indexMir, tmpCol);
} }
indexSet += offset; // offset/phase indexSet += offset; // offset/phase
if (indexSet >= stop) indexSet -= len; // wrap if (indexSet >= stop) indexSet -= len; // wrap
strip.setPixelColor(indexSet, col); #ifndef WLED_DISABLE_MODE_BLEND
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true);
#endif
strip.setPixelColor(indexSet, tmpCol);
} }
} }
} }
@ -844,7 +979,7 @@ void Segment::fade_out(uint8_t rate) {
const uint16_t rows = virtualHeight(); // will be 1 for 1D const uint16_t rows = virtualHeight(); // will be 1 for 1D
rate = (255-rate) >> 1; rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1; float mappedRate = float(rate) +1.1f;
uint32_t color = colors[1]; // SEGCOLOR(1); // target color uint32_t color = colors[1]; // SEGCOLOR(1); // target color
int w2 = W(color); int w2 = W(color);
@ -1073,14 +1208,17 @@ void WS2812FX::service() {
_isServicing = true; _isServicing = true;
_segment_index = 0; _segment_index = 0;
Segment::handleRandomPalette(); // move it into for loop when each segment has individual random palette
for (segment &seg : _segments) { for (segment &seg : _segments) {
// process transition (mode changes in the middle of transition) // process transition (mode changes in the middle of transition)
seg.handleTransition(); seg.handleTransition();
// reset the segment runtime data if needed // reset the segment runtime data if needed
seg.resetIfRequired(); seg.resetIfRequired();
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 (seg.isActive() && (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))) if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
{ {
doShow = true; doShow = true;
uint16_t delay = FRAMETIME; uint16_t delay = FRAMETIME;
@ -1095,10 +1233,25 @@ void WS2812FX::service() {
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB); if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB);
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]); for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
// effect blending (execute previous effect) // Effect blending
// actual code may be a bit more involved as effects have runtime data including allocated memory // When two effects are being blended, each may have different segment data, this
//if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress()); // data needs to be saved first and then restored before running previous/transitional mode.
delay = (*_mode[seg.currentMode(seg.mode)])(); // The blending will largely depend on the effect behaviour since actual output (LEDs) may be
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
// would need to be allocated for each effect and then blended together for each pixel.
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(seg.mode); // this will return old mode while in transition
delay = (*_mode[seg.mode])(); // run new/current mode
#ifndef WLED_DISABLE_MODE_BLEND
if (seg.mode != tmpMode) {
Segment::tmpsegd_t _tmpSegData;
Segment::modeBlend(true); // set semaphore
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
uint16_t d2 = (*_mode[tmpMode])(); // run old mode
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
delay = MIN(delay,d2); // use shortest delay
Segment::modeBlend(false); // unset semaphore
}
#endif
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++; if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
} }
@ -1224,19 +1377,9 @@ void WS2812FX::show(void) {
show_callback callback = _callback; show_callback callback = _callback;
if (callback) callback(); if (callback) callback();
#ifdef WLED_DEBUG
static unsigned long sumMicros = 0, sumCurrent = 0;
static size_t calls = 0;
unsigned long microsStart = micros();
#endif
uint8_t newBri = estimateCurrentAndLimitBri(); uint8_t newBri = estimateCurrentAndLimitBri();
busses.setBrightness(newBri); // "repaints" all pixels if brightness changed busses.setBrightness(newBri); // "repaints" all pixels if brightness changed
#ifdef WLED_DEBUG
sumCurrent += micros() - microsStart;
#endif
// some buses send asynchronously and this method will return before // some buses send asynchronously and this method will return before
// all of the data has been sent. // all of the data has been sent.
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
@ -1247,15 +1390,6 @@ void WS2812FX::show(void) {
// or async show has a separate buffer (ESP32 RMT and I2S are ok) // or async show has a separate buffer (ESP32 RMT and I2S are ok)
if (newBri < _brightness) busses.setBrightness(_brightness); if (newBri < _brightness) busses.setBrightness(_brightness);
#ifdef WLED_DEBUG
sumMicros += micros() - microsStart;
if (++calls == 100) {
DEBUG_PRINTF("%d show calls: %lu[us] avg: %lu[us] (current: %lu[us] avg: %lu[us])\n", calls, sumMicros, sumMicros/calls, sumCurrent, sumCurrent/calls);
sumMicros = sumCurrent = 0;
calls = 0;
}
#endif
unsigned long now = millis(); unsigned long now = millis();
size_t diff = now - _lastShow; size_t diff = now - _lastShow;
size_t fpsCurr = 200; size_t fpsCurr = 200;
@ -1292,9 +1426,7 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) {
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(_transitionDur); // set effect transitions _segments[segid].setMode(m); // do not load defaults
//_segments[segid].markForReset();
_segments[segid].mode = m;
} }
} }

View File

@ -145,9 +145,13 @@ void BusDigital::show() {
} }
uint16_t pix = i; uint16_t pix = i;
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
else pix += _skip; pix += _skip;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
} }
#if !defined(STATUSLED) || STATUSLED>=0
if (_skip) PolyBus::setPixelColor(_busPtr, _iType, 0, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
#endif
for (int i=1; i<_skip; i++) PolyBus::setPixelColor(_busPtr, _iType, i, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
} }
PolyBus::show(_busPtr, _iType, !_buffering); // faster if buffer consistency is not important PolyBus::show(_busPtr, _iType, !_buffering); // faster if buffer consistency is not important
} }
@ -207,7 +211,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
if (Bus::hasWhite(_type)) _data[offset] = W(c); if (Bus::hasWhite(_type)) _data[offset] = W(c);
} else { } else {
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
else pix += _skip; pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
uint16_t pOld = pix; uint16_t pOld = pix;
@ -238,7 +242,7 @@ uint32_t BusDigital::getPixelColor(uint16_t pix) {
return c; return c;
} else { } else {
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
else pix += _skip; pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri); uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs

View File

@ -21,6 +21,7 @@ void shortPressAction(uint8_t b)
case 1: ++effectCurrent %= strip.getModeCount(); stateChanged = true; colorUpdated(CALL_MODE_BUTTON); break; case 1: ++effectCurrent %= strip.getModeCount(); stateChanged = true; colorUpdated(CALL_MODE_BUTTON); break;
} }
} else { } else {
unloadPlaylist(); // applying a preset unloads the playlist
applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
} }
@ -42,6 +43,7 @@ void longPressAction(uint8_t b)
case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
} }
} else { } else {
unloadPlaylist(); // applying a preset unloads the playlist
applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
} }
@ -63,6 +65,7 @@ void doublePressAction(uint8_t b)
case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break; case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
} }
} else { } else {
unloadPlaylist(); // applying a preset unloads the playlist
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET);
} }
@ -262,7 +265,7 @@ void handleButton()
shortPressAction(b); shortPressAction(b);
buttonPressedBefore[b] = true; buttonPressedBefore[b] = true;
buttonPressedTime[b] = now; // continually update (for debouncing to work in release handler) buttonPressedTime[b] = now; // continually update (for debouncing to work in release handler)
return; continue;
} }
if (!buttonPressedBefore[b]) buttonPressedTime[b] = now; if (!buttonPressedBefore[b]) buttonPressedTime[b] = now;
@ -283,7 +286,7 @@ void handleButton()
// released after rising-edge short press action // released after rising-edge short press action
if (macroButton[b] && macroButton[b] == macroLongPress[b] && macroButton[b] == macroDoublePress[b]) { if (macroButton[b] && macroButton[b] == macroLongPress[b] && macroButton[b] == macroDoublePress[b]) {
if (dur > WLED_DEBOUNCE_THRESHOLD) buttonPressedBefore[b] = false; // debounce, blocks button for 50 ms once it has been released if (dur > WLED_DEBOUNCE_THRESHOLD) buttonPressedBefore[b] = false; // debounce, blocks button for 50 ms once it has been released
return; continue;
} }
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} // too short "press", debounce if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} // too short "press", debounce

View File

@ -442,14 +442,14 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"]; JsonObject if_mqtt = interfaces["mqtt"];
CJSON(mqttEnabled, if_mqtt["en"]); CJSON(mqttEnabled, if_mqtt["en"]);
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33); getStringFromJson(mqttServer, if_mqtt[F("broker")], MQTT_MAX_SERVER_LEN+1);
CJSON(mqttPort, if_mqtt["port"]); // 1883 CJSON(mqttPort, if_mqtt["port"]); // 1883
getStringFromJson(mqttUser, if_mqtt[F("user")], 41); getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
getStringFromJson(mqttPass, if_mqtt["psk"], 65); //normally not present due to security getStringFromJson(mqttPass, if_mqtt["psk"], 65); //normally not present due to security
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41); getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test" getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], MQTT_MAX_TOPIC_LEN+1); // "wled/test"
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // "" getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], MQTT_MAX_TOPIC_LEN+1); // ""
CJSON(retainMqttMsg, if_mqtt[F("rtn")]); CJSON(retainMqttMsg, if_mqtt[F("rtn")]);
#endif #endif

View File

@ -147,8 +147,9 @@
#define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h" #define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h"
#define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h #define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h
#define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h #define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h
#define USERMOD_ID_KLIPPER 40 // Usermod Klipper percentage #define USERMOD_ID_KLIPPER 40 //Usermod Klipper percentage
#define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h" #define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h"
#define USERMOD_ID_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h"
//Access point behavior //Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

View File

@ -683,6 +683,7 @@ ${i.opt&0x100?inforow("Debug","<button class=\"btn btn-xs\" onclick=\"requestJso
${inforow("Build",i.vid)} ${inforow("Build",i.vid)}
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")} ${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
${inforow("Uptime",getRuntimeStr(i.uptime))} ${inforow("Uptime",getRuntimeStr(i.uptime))}
${inforow("Time",i.time)}
${inforow("Free heap",heap," kB")} ${inforow("Free heap",heap," kB")}
${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""} ${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""}
${inforow("Estimated current",pwru)} ${inforow("Estimated current",pwru)}

View File

@ -523,6 +523,7 @@ ${urows}
${inforow("Build",i.vid)} ${inforow("Build",i.vid)}
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")} ${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
${inforow("Uptime",getRuntimeStr(i.uptime))} ${inforow("Uptime",getRuntimeStr(i.uptime))}
${inforow("Time",i.time)}
${inforow("Free heap",heap," kB")} ${inforow("Free heap",heap," kB")}
${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""} ${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""}
${inforow("Estimated current",pwru)} ${inforow("Estimated current",pwru)}

View File

@ -1754,7 +1754,7 @@ const uint8_t PAGE_settings_sec[] PROGMEM = {
0xb7, 0x4d, 0x92, 0x26, 0x11, 0xda, 0xcf, 0x48, 0x28, 0xb8, 0x59, 0x35, 0x09, 0x71, 0x75, 0xef, 0xb7, 0x4d, 0x92, 0x26, 0x11, 0xda, 0xcf, 0x48, 0x28, 0xb8, 0x59, 0x35, 0x09, 0x71, 0x75, 0xef,
0x9d, 0x48, 0x9d, 0x28, 0xa5, 0xe6, 0x52, 0xf4, 0xa8, 0x07, 0xef, 0xa1, 0x4e, 0xc7, 0x7a, 0x46, 0x9d, 0x48, 0x9d, 0x28, 0xa5, 0xe6, 0x52, 0xf4, 0xa8, 0x07, 0xef, 0xa1, 0x4e, 0xc7, 0x7a, 0x46,
0x9f, 0xbb, 0x3e, 0x4d, 0x72, 0x94, 0x48, 0x3e, 0xa4, 0x61, 0x0a, 0x82, 0x0e, 0xbb, 0x17, 0x9a, 0x9f, 0xbb, 0x3e, 0x4d, 0x72, 0x94, 0x48, 0x3e, 0xa4, 0x61, 0x0a, 0x82, 0x0e, 0xbb, 0x17, 0x9a,
0x68, 0x86, 0xf5, 0xc3, 0xfd, 0x97, 0x61, 0x7f, 0x6f, 0xf2, 0x62, 0xcd, 0x55, 0x7f, 0x46, 0xc2, 0x68, 0x86, 0xf5, 0xc3, 0xfd, 0x97, 0x61, 0x7f, 0x6f, 0xf2, 0x72, 0xcd, 0x55, 0x7f, 0x46, 0xc2,
0x52, 0xce, 0x65, 0xcf, 0x5d, 0xdb, 0xa8, 0x83, 0x55, 0xda, 0xec, 0x81, 0x0d, 0xf7, 0x12, 0x2d, 0x52, 0xce, 0x65, 0xcf, 0x5d, 0xdb, 0xa8, 0x83, 0x55, 0xda, 0xec, 0x81, 0x0d, 0xf7, 0x12, 0x2d,
0x52, 0x49, 0x41, 0xda, 0x79, 0x28, 0x7f, 0x7b, 0x29, 0xaa, 0xb5, 0xa0, 0x0b, 0x28, 0xf8, 0x4f, 0x52, 0x49, 0x41, 0xda, 0x79, 0x28, 0x7f, 0x7b, 0x29, 0xaa, 0xb5, 0xa0, 0x0b, 0x28, 0xf8, 0x4f,
0x8a, 0x9a, 0x46, 0x4d, 0x29, 0x12, 0x09, 0xce, 0xb1, 0xa8, 0x08, 0xf3, 0x75, 0xea, 0x76, 0x4e, 0x8a, 0x9a, 0x46, 0x4d, 0x29, 0x12, 0x09, 0xce, 0xb1, 0xa8, 0x08, 0xf3, 0x75, 0xea, 0x76, 0x4e,
@ -1768,7 +1768,7 @@ const uint8_t PAGE_settings_sec[] PROGMEM = {
0x19, 0xc6, 0xa0, 0x40, 0x82, 0x50, 0x71, 0x5d, 0x2e, 0x5a, 0x26, 0x30, 0xb2, 0xe4, 0x94, 0xb3, 0x19, 0xc6, 0xa0, 0x40, 0x82, 0x50, 0x71, 0x5d, 0x2e, 0x5a, 0x26, 0x30, 0xb2, 0xe4, 0x94, 0xb3,
0xee, 0x93, 0x02, 0x73, 0x5f, 0x09, 0x88, 0xea, 0x69, 0x49, 0xcd, 0xab, 0x94, 0x27, 0xc4, 0x12, 0xee, 0x93, 0x02, 0x73, 0x5f, 0x09, 0x88, 0xea, 0x69, 0x49, 0xcd, 0xab, 0x94, 0x27, 0xc4, 0x12,
0xf5, 0x67, 0x98, 0xdf, 0x6d, 0x64, 0xbf, 0xef, 0x63, 0x3b, 0x7f, 0xaa, 0x91, 0xed, 0x51, 0xb5, 0xf5, 0x67, 0x98, 0xdf, 0x6d, 0x64, 0xbf, 0xef, 0x63, 0x3b, 0x7f, 0xaa, 0x91, 0xed, 0x51, 0xb5,
0xc1, 0x0f, 0xf5, 0xef, 0xd4, 0xcc, 0xd3, 0x77, 0xe0, 0xff, 0x02, 0xe8, 0x93, 0xa8, 0x82, 0x17, 0xc1, 0x0f, 0xf5, 0xef, 0xd4, 0xcc, 0xd3, 0x77, 0xe0, 0xff, 0x02, 0x6f, 0x8b, 0xcf, 0x3d, 0x17,
0x16, 0x00, 0x00 0x16, 0x00, 0x00
}; };

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -210,7 +210,7 @@ void sendImprovInfoResponse() {
//Use serverDescription if it has been changed from the default "WLED", else mDNS name //Use serverDescription if it has been changed from the default "WLED", else mDNS name
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0); bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
char vString[20]; char vString[20];
sprintf_P(vString, PSTR("0.14.0-b3/%i"), VERSION); sprintf_P(vString, PSTR("0.14.0-b4/%i"), VERSION);
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription}; const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str); sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);

View File

@ -29,8 +29,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
id = strip.getSegmentsNum()-1; // segments are added at the end of list id = strip.getSegmentsNum()-1; // segments are added at the end of list
} }
//DEBUG_PRINTLN("-- JSON deserialize segment.");
Segment& seg = strip.getSegment(id); Segment& seg = strip.getSegment(id);
//DEBUG_PRINTF("-- Original segment: %p\n", &seg);
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
//DEBUG_PRINTF("-- Duplicate segment: %p\n", &prev);
uint16_t start = elem["start"] | seg.start; uint16_t start = elem["start"] | seg.start;
if (stop < 0) { if (stop < 0) {
@ -347,7 +350,9 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
JsonObject udpn = root["udpn"]; JsonObject udpn = root["udpn"];
notifyDirect = udpn["send"] | notifyDirect; notifyDirect = udpn["send"] | notifyDirect;
syncGroups = udpn["sgrp"] | syncGroups;
receiveNotifications = udpn["recv"] | receiveNotifications; receiveNotifications = udpn["recv"] | receiveNotifications;
receiveGroups = udpn["rgrp"] | receiveGroups;
if ((bool)udpn[F("nn")]) callMode = CALL_MODE_NO_NOTIFY; //send no notification just for this request if ((bool)udpn[F("nn")]) callMode = CALL_MODE_NO_NOTIFY; //send no notification just for this request
unsigned long timein = root["time"] | UINT32_MAX; //backup time source if NTP not synced unsigned long timein = root["time"] | UINT32_MAX; //backup time source if NTP not synced
@ -564,6 +569,8 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
JsonObject udpn = root.createNestedObject("udpn"); JsonObject udpn = root.createNestedObject("udpn");
udpn["send"] = notifyDirect; udpn["send"] = notifyDirect;
udpn["recv"] = receiveNotifications; udpn["recv"] = receiveNotifications;
udpn["sgrp"] = syncGroups;
udpn["rgrp"] = receiveGroups;
root[F("lor")] = realtimeOverride; root[F("lor")] = realtimeOverride;
} }
@ -735,6 +742,10 @@ void serializeInfo(JsonObject root)
#endif #endif
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967; root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
char time[32];
getTimeString(time);
root[F("time")] = time;
usermods.addToJsonInfo(root); usermods.addToJsonInfo(root);
uint16_t os = 0; uint16_t os = 0;
@ -971,9 +982,10 @@ void serializeNodes(JsonObject root)
// deserializes mode data string into JsonArray // deserializes mode data string into JsonArray
void serializeModeData(JsonArray fxdata) void serializeModeData(JsonArray fxdata)
{ {
char lineBuffer[128]; char lineBuffer[256];
for (size_t i = 0; i < strip.getModeCount(); i++) { for (size_t i = 0; i < strip.getModeCount(); i++) {
strncpy_P(lineBuffer, strip.getModeData(i), 127); strncpy_P(lineBuffer, strip.getModeData(i), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
if (lineBuffer[0] != 0) { if (lineBuffer[0] != 0) {
char* dataPtr = strchr(lineBuffer,'@'); char* dataPtr = strchr(lineBuffer,'@');
if (dataPtr) fxdata.add(dataPtr+1); if (dataPtr) fxdata.add(dataPtr+1);
@ -984,10 +996,12 @@ void serializeModeData(JsonArray fxdata)
// deserializes mode names string into JsonArray // deserializes mode names string into JsonArray
// also removes effect data extensions (@...) from deserialised names // also removes effect data extensions (@...) from deserialised names
void serializeModeNames(JsonArray arr) { void serializeModeNames(JsonArray arr)
char lineBuffer[128]; {
char lineBuffer[256];
for (size_t i = 0; i < strip.getModeCount(); i++) { for (size_t i = 0; i < strip.getModeCount(); i++) {
strncpy_P(lineBuffer, strip.getModeData(i), 127); strncpy_P(lineBuffer, strip.getModeData(i), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
if (lineBuffer[0] != 0) { if (lineBuffer[0] != 0) {
char* dataPtr = strchr(lineBuffer,'@'); char* dataPtr = strchr(lineBuffer,'@');
if (dataPtr) *dataPtr = 0; // terminate mode data after name if (dataPtr) *dataPtr = 0; // terminate mode data after name

View File

@ -37,12 +37,12 @@ void applyValuesToSelectedSegs()
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;} if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;} if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette); stateChanged = true;} if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette);}
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent); stateChanged = true;} if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent);}
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]); uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]); uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;} if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0);}
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1); stateChanged = true;} if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1);}
} }
} }
@ -161,6 +161,8 @@ void stateUpdated(byte callMode) {
void updateInterfaces(uint8_t callMode) void updateInterfaces(uint8_t callMode)
{ {
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
sendDataWs(); sendDataWs();
lastInterfaceUpdate = millis(); lastInterfaceUpdate = millis();
if (callMode == CALL_MODE_WS_SEND) return; if (callMode == CALL_MODE_WS_SEND) return;
@ -179,7 +181,7 @@ void updateInterfaces(uint8_t callMode)
void handleTransitions() void handleTransitions()
{ {
//handle still pending interface update //handle still pending interface update
if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > INTERFACE_UPDATE_COOLDOWN) updateInterfaces(interfaceUpdateCallMode); updateInterfaces(interfaceUpdateCallMode);
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
if (doPublishMqtt) publishMqtt(); if (doPublishMqtt) publishMqtt();
#endif #endif

View File

@ -112,7 +112,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
if (playlistEndPreset == 255 && currentPreset > 0) playlistEndPreset = currentPreset; if (playlistEndPreset == 255 && currentPreset > 0) playlistEndPreset = currentPreset;
if (playlistEndPreset > 250) playlistEndPreset = 0; if (playlistEndPreset > 250) playlistEndPreset = 0;
shuffle = shuffle || playlistObj["r"]; shuffle = shuffle || playlistObj["r"];
if (shuffle) playlistOptions += PL_OPTION_SHUFFLE; if (shuffle) playlistOptions |= PL_OPTION_SHUFFLE;
currentPlaylist = presetId; currentPlaylist = presetId;
DEBUG_PRINTLN(F("Playlist loaded.")); DEBUG_PRINTLN(F("Playlist loaded."));
@ -156,7 +156,7 @@ void serializePlaylist(JsonObject sObj) {
JsonArray ps = playlist.createNestedArray("ps"); JsonArray ps = playlist.createNestedArray("ps");
JsonArray dur = playlist.createNestedArray("dur"); JsonArray dur = playlist.createNestedArray("dur");
JsonArray transition = playlist.createNestedArray(F("transition")); JsonArray transition = playlist.createNestedArray(F("transition"));
playlist[F("repeat")] = (playlistIndex < 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running) playlist[F("repeat")] = (playlistIndex < 0 && playlistRepeat > 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running)
playlist["end"] = playlistEndPreset; playlist["end"] = playlistEndPreset;
playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE; playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE;
for (int i=0; i<playlistLen; i++) { for (int i=0; i<playlistLen; i++) {

View File

@ -39,7 +39,7 @@ typedef struct message_structure {
} message_structure; } message_structure;
static int esp_now_state = ESP_NOW_STATE_UNINIT; static int esp_now_state = ESP_NOW_STATE_UNINIT;
static uint32_t last_seq = -1; static uint32_t last_seq = UINT32_MAX;
static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED; static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
static message_structure incoming; static message_structure incoming;
@ -168,7 +168,7 @@ void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
void handleRemote() { void handleRemote() {
if (enable_espnow_remote) { if (enable_espnow_remote) {
if (esp_now_state == ESP_NOW_STATE_UNINIT) { if ((esp_now_state == ESP_NOW_STATE_UNINIT) && (interfacesInited || apActive)) { // ESPNOW requires Wifi to be initialized (either STA, or AP Mode)
DEBUG_PRINTLN(F("Initializing ESP_NOW listener")); DEBUG_PRINTLN(F("Initializing ESP_NOW listener"));
// Init ESP-NOW // Init ESP-NOW
if (esp_now_init() != 0) { if (esp_now_init() != 0) {

View File

@ -347,14 +347,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
mqttEnabled = request->hasArg(F("MQ")); mqttEnabled = request->hasArg(F("MQ"));
strlcpy(mqttServer, request->arg(F("MS")).c_str(), 33); strlcpy(mqttServer, request->arg(F("MS")).c_str(), MQTT_MAX_SERVER_LEN+1);
t = request->arg(F("MQPORT")).toInt(); t = request->arg(F("MQPORT")).toInt();
if (t > 0) mqttPort = t; if (t > 0) mqttPort = t;
strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41); strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41);
if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 65); if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 65);
strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41); strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41);
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33); strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), MQTT_MAX_TOPIC_LEN+1);
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33); strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), MQTT_MAX_TOPIC_LEN+1);
buttonPublishMqtt = request->hasArg(F("BM")); buttonPublishMqtt = request->hasArg(F("BM"));
retainMqttMsg = request->hasArg(F("RT")); retainMqttMsg = request->hasArg(F("RT"));
#endif #endif

View File

@ -177,6 +177,10 @@
#include "../usermods/boblight/boblight.h" #include "../usermods/boblight/boblight.h"
#endif #endif
#ifdef USERMOD_INTERNAL_TEMPERATURE
#include "../usermods/Internal_Temperature_v2/usermod_internal_temperature.h"
#endif
#if defined(WLED_USE_SD_MMC) || defined(WLED_USE_SD_SPI) #if defined(WLED_USE_SD_MMC) || defined(WLED_USE_SD_SPI)
// This include of SD.h and SD_MMC.h must happen here, else they won't be // This include of SD.h and SD_MMC.h must happen here, else they won't be
// resolved correctly (when included in mod's header only) // resolved correctly (when included in mod's header only)
@ -365,4 +369,8 @@ void registerUsermods()
#ifdef USERMOD_SHT #ifdef USERMOD_SHT
usermods.add(new ShtUsermod()); usermods.add(new ShtUsermod());
#endif #endif
#ifdef USERMOD_INTERNAL_TEMPERATURE
usermods.add(new InternalTemperatureUsermod());
#endif
} }

View File

@ -148,8 +148,14 @@ bool oappendi(int i)
bool oappend(const char* txt) bool oappend(const char* txt)
{ {
uint16_t len = strlen(txt); uint16_t len = strlen(txt);
if (olen + len >= SETTINGS_STACK_BUF_SIZE) if (olen + len >= SETTINGS_STACK_BUF_SIZE) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("oappend() buffer overflow. Cannnot append "));
DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\""));
DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\""));
#endif
return false; // buffer full return false; // buffer full
}
strcpy(obuf + olen, txt); strcpy(obuf + olen, txt);
olen += len; olen += len;
return true; return true;
@ -233,7 +239,8 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
if (mode < strip.getModeCount()) { if (mode < strip.getModeCount()) {
char lineBuffer[256]; char lineBuffer[256];
//strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); //strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode])));
strcpy_P(lineBuffer, strip.getModeData(mode)); strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
size_t len = strlen(lineBuffer); size_t len = strlen(lineBuffer);
size_t j = 0; size_t j = 0;
for (; j < maxLen && j < len; j++) { for (; j < maxLen && j < len; j++) {
@ -245,6 +252,12 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
} else return 0; } else return 0;
} }
if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) {
snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode);
dest[maxLen-1] = '\0';
return strlen(dest);
}
uint8_t qComma = 0; uint8_t qComma = 0;
bool insideQuotes = false; bool insideQuotes = false;
uint8_t printedChars = 0; uint8_t printedChars = 0;
@ -355,9 +368,9 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
int16_t extractModeDefaults(uint8_t mode, const char *segVar) int16_t extractModeDefaults(uint8_t mode, const char *segVar)
{ {
if (mode < strip.getModeCount()) { if (mode < strip.getModeCount()) {
char lineBuffer[128] = ""; char lineBuffer[256];
strncpy_P(lineBuffer, strip.getModeData(mode), 127); strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[127] = '\0'; // terminate string lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
if (lineBuffer[0] != 0) { if (lineBuffer[0] != 0) {
char* startPtr = strrchr(lineBuffer, ';'); // last ";" in FX data char* startPtr = strrchr(lineBuffer, ';'); // last ";" in FX data
if (!startPtr) return -1; if (!startPtr) return -1;

View File

@ -195,12 +195,15 @@ void WLED::loop()
#if WLED_WATCHDOG_TIMEOUT > 0 #if WLED_WATCHDOG_TIMEOUT > 0
// we finished our mainloop, reset the watchdog timer // we finished our mainloop, reset the watchdog timer
if (!strip.isUpdating()) static unsigned long lastWDTFeed = 0;
if (!strip.isUpdating() || millis() - lastWDTFeed > (WLED_WATCHDOG_TIMEOUT*500)) {
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
esp_task_wdt_reset(); esp_task_wdt_reset();
#else #else
ESP.wdtFeed(); ESP.wdtFeed();
#endif #endif
lastWDTFeed = millis();
}
#endif #endif
if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration

View File

@ -3,12 +3,12 @@
/* /*
Main sketch, global variable declarations Main sketch, global variable declarations
@title WLED project sketch @title WLED project sketch
@version 0.14.0-b3 @version 0.14.0-b4
@author Christian Schwinne @author Christian Schwinne
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2307180 #define VERSION 2309050
//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
@ -429,12 +429,18 @@ WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count numbe
// mqtt // mqtt
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
#ifndef MQTT_MAX_TOPIC_LEN
#define MQTT_MAX_TOPIC_LEN 32
#endif
#ifndef MQTT_MAX_SERVER_LEN
#define MQTT_MAX_SERVER_LEN 32
#endif
WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL);
WLED_GLOBAL bool mqttEnabled _INIT(false); WLED_GLOBAL bool mqttEnabled _INIT(false);
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
WLED_GLOBAL char mqttDeviceTopic[33] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac)
WLED_GLOBAL char mqttGroupTopic[33] _INIT("wled/all"); // second MQTT topic (for example to group devices) WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices)
WLED_GLOBAL char mqttServer[33] _INIT(""); // both domains and IPs should work (no SSL) WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL)
WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID

View File

@ -478,6 +478,7 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == SUBPAGE_SYNC) if (subPage == SUBPAGE_SYNC)
{ {
char nS[32];
sappend('v',SET_F("UP"),udpPort); sappend('v',SET_F("UP"),udpPort);
sappend('v',SET_F("U2"),udpPort2); sappend('v',SET_F("U2"),udpPort2);
sappend('v',SET_F("GS"),syncGroups); sappend('v',SET_F("GS"),syncGroups);
@ -534,6 +535,9 @@ void getSettingsJS(byte subPage, char* dest)
sappends('s',SET_F("MG"),mqttGroupTopic); sappends('s',SET_F("MG"),mqttGroupTopic);
sappend('c',SET_F("BM"),buttonPublishMqtt); sappend('c',SET_F("BM"),buttonPublishMqtt);
sappend('c',SET_F("RT"),retainMqttMsg); sappend('c',SET_F("RT"),retainMqttMsg);
oappend(SET_F("d.Sf.MD.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";"));
oappend(SET_F("d.Sf.MG.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";"));
oappend(SET_F("d.Sf.MS.maxlength=")); oappend(itoa(MQTT_MAX_SERVER_LEN,nS,10)); oappend(SET_F(";"));
#else #else
oappend(SET_F("toggle('MQTT');")); // hide MQTT settings oappend(SET_F("toggle('MQTT');")); // hide MQTT settings
#endif #endif