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

This commit is contained in:
Alerson Jorge 2023-07-20 13:32:35 -03:00
commit cd6b3d7dee
60 changed files with 5164 additions and 5364 deletions

View File

@ -1,5 +1,38 @@
## WLED changelog
#### Build 2307130
- larger `oappend()` stack buffer (3.5k) for ESP32
- Preset cycle bugfix (#3262)
- Rotary encoder ALT fix for large LED count (#3276)
- effect updates (2D Plasmaball), `blur()` speedup
- On/Off toggle from nodes view (may show unknow device type on older versions) (#3291)
- various fixes and improvements (ABL, crashes when changing presets with different segments)
#### Build 2306270
- ESP-NOW remote support (#3237)
- Pixel Magic tool (display pixel art) (#3249)
- Websocket (peek) fallback when connection cannot be established, WS retries (#3267)
- Add WiFi network scan RPC command to Improv Serial (#3271)
- Longer (custom option available) segment name for ESP32
- various fixes and improvements
#### Build 2306210
- 0.14.0-b3 release
- respect global I2C in all usermods (no local initilaisation of I2C bus)
- Multi relay usermod compile-time enabled option (-D MULTI_RELAY_ENABLED=true|false)
#### Build 2306180
- Added client-side option for applying effect defaults from metadata
- Improved ESP8266 stability by reducing WebSocket response resends
- Updated ESP8266 core to 3.1.2
#### Build 2306141
- Lissajous improvements
- Scrolling Text improvements (leading 0)
#### Build 2306140
- Add settings PIN (un)locking to JSON post API
#### Build 2306130
- Bumped version to 0.14-b3 (beta 3)
- added pin dropdowns in LED preferences (not for LED pins) and usermods

6
package-lock.json generated
View File

@ -1409,9 +1409,9 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="
},
"semver-diff": {
"version": "2.1.0",

View File

@ -10,7 +10,7 @@
# ------------------------------------------------------------------------------
# CI binaries
;; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
# Release binaries
@ -40,6 +40,8 @@ default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_
; default_envs = esp32dev_qio80
; default_envs = esp32_eth_ota1mapp
; default_envs = esp32s2_saola
; default_envs = esp32c3dev
; default_envs = lolin_s2_mini
src_dir = ./wled00
data_dir = ./wled00/data
@ -60,13 +62,14 @@ arduino_core_2_7_4 = espressif8266@2.6.2
arduino_core_3_0_0 = espressif8266@3.0.0
arduino_core_3_2_0 = espressif8266@3.2.0
arduino_core_4_1_0 = espressif8266@4.1.0
arduino_core_3_1_2 = espressif8266@4.2.0
# Development platforms
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
# Platform to use for ESP8266
platform_wled_default = ${common.arduino_core_4_1_0}
platform_wled_default = ${common.arduino_core_3_1_2}
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
platform_packages = platformio/framework-arduinoespressif8266
@ -459,8 +462,8 @@ board = esp32-c3-devkitm-1
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3
-D WLED_WATCHDOG_TIMEOUT=0
; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
;-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
upload_speed = 460800
build_unflags = ${common.build_unflags}
lib_deps = ${esp32c3.lib_deps}
@ -572,10 +575,10 @@ platform = ${esp32s2.platform}
platform_packages = ${esp32s2.platform_packages}
board = lolin_s2_mini
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
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=0
-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_DFU_ON_BOOT=0
-DLOLIN_WIFI_FIX ; seems to work much better with this

View File

@ -390,12 +390,6 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
method: "gzip",
filter: "html-minify",
},
{
file: "liveviewws.htm",
name: "PAGE_liveviewws",
method: "gzip",
filter: "html-minify",
},
{
file: "liveviewws2D.htm",
name: "PAGE_liveviewws2D",

View File

@ -113,8 +113,7 @@ private:
public:
void setup()
{
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; // allocate pins
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) return;
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
sensorFound = lightMeter.begin();
initDone = true;
}
@ -174,7 +173,9 @@ public:
user = root.createNestedObject(F("u"));
JsonArray lux_json = user.createNestedArray(F("Luminance"));
if (!sensorFound) {
if (!enabled) {
lux_json.add(F("disabled"));
} else if (!sensorFound) {
// if no sensor
lux_json.add(F("BH1750 "));
lux_json.add(F("Not Found"));

View File

@ -184,8 +184,7 @@ private:
public:
void setup()
{
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; // allocate pins
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { sensorType=0; return; }
if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; }
if (!bme.begin())
{

View File

@ -271,10 +271,9 @@ void PIRsensorSwitch::publishMqtt(const char* state)
#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("/motion"));
mqtt->publish(subuf, 0, false, state);
char buf[64];
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
mqtt->publish(buf, 0, false, state);
}
#endif
}

View File

@ -12,8 +12,7 @@ class RTCUsermod : public Usermod {
public:
void setup() {
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { disabled = true; return; }
if (i2c_scl<0 || i2c_sda<0) { disabled = true; return; }
RTC.begin();
time_t rtcTime = RTC.get();
if (rtcTime) {
@ -25,8 +24,8 @@ class RTCUsermod : public Usermod {
}
void loop() {
if (strip.isUpdating()) return;
if (!disabled && toki.isTick()) {
if (disabled || strip.isUpdating()) return;
if (toki.isTick()) {
time_t t = toki.second();
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
}

View File

@ -50,8 +50,7 @@ class UsermodVL53L0XGestures : public Usermod {
public:
void setup() {
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
sensor.setTimeout(150);
if (!sensor.init())

View File

@ -1149,6 +1149,13 @@ class AudioReactive : public Usermod {
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin);
break;
#endif
case 6:
DEBUGSR_PRINTLN(F("AR: ES8388 Source"));
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE);
delay(100);
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
break;
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// ADC over I2S is only possible on "classic" ESP32
case 0:
@ -1738,6 +1745,8 @@ class AudioReactive : public Usermod {
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
oappend(SET_F("addOption(dd,'Generic I2S PDM',5);"));
#endif
oappend(SET_F("addOption(dd,'ES8388',6);"));
oappend(SET_F("dd=addDropdown('AudioReactive','config:AGC');"));
oappend(SET_F("addOption(dd,'Off',0);"));
oappend(SET_F("addOption(dd,'Normal',1);"));

View File

@ -427,6 +427,122 @@ public:
}
};
/* ES8388 Sound Modude
This is an I2S sound processing unit that requires ininitialization over
I2C before I2S data can be received.
*/
class ES8388Source : public I2SSource {
private:
void _es8388I2cWrite(uint8_t reg, uint8_t val) {
#ifndef ES8388_ADDR
Wire.beginTransmission(0x10);
#define ES8388_ADDR 0x10 // default address
#else
Wire.beginTransmission(ES8388_ADDR);
#endif
Wire.write((uint8_t)reg);
Wire.write((uint8_t)val);
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
if (i2cErr != 0) {
DEBUGSR_PRINTF("AR: ES8388 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X).\n", i2cErr, ES8388_ADDR, reg, val);
}
}
void _es8388InitAdc() {
// https://dl.radxa.com/rock2/docs/hw/ds/ES8388%20user%20Guide.pdf Section 10.1
// http://www.everest-semi.com/pdf/ES8388%20DS.pdf Better spec sheet, more clear.
// https://docs.google.com/spreadsheets/d/1CN3MvhkcPVESuxKyx1xRYqfUit5hOdsG45St9BCUm-g/edit#gid=0 generally
// Sets ADC to around what AudioReactive expects, and loops line-in to line-out/headphone for monitoring.
// Registries are decimal, settings are binary as that's how everything is listed in the docs
// ...which makes it easier to reference the docs.
//
_es8388I2cWrite( 8,0b00000000); // I2S to slave
_es8388I2cWrite( 2,0b11110011); // Power down DEM and STM
_es8388I2cWrite(43,0b10000000); // Set same LRCK
_es8388I2cWrite( 0,0b00000101); // Set chip to Play & Record Mode
_es8388I2cWrite(13,0b00000010); // Set MCLK/LRCK ratio to 256
_es8388I2cWrite( 1,0b01000000); // Power up analog and lbias
_es8388I2cWrite( 3,0b00000000); // Power up ADC, Analog Input, and Mic Bias
_es8388I2cWrite( 4,0b11111100); // Power down DAC, Turn on LOUT1 and ROUT1 and LOUT2 and ROUT2 power
_es8388I2cWrite( 2,0b01000000); // Power up DEM and STM and undocumented bit for "turn on line-out amp"
// #define use_es8388_mic
#ifdef use_es8388_mic
// The mics *and* line-in are BOTH connected to LIN2/RIN2 on the AudioKit
// so there's no way to completely eliminate the mics. It's also hella noisy.
// Line-in works OK on the AudioKit, generally speaking, as the mics really need
// amplification to be noticable in a quiet room. If you're in a very loud room,
// the mics on the AudioKit WILL pick up sound even in line-in mode.
// TL;DR: Don't use the AudioKit for anything, use the LyraT.
//
// The LyraT does a reasonable job with mic input as configured below.
// Pick one of these. If you have to use the mics, use a LyraT over an AudioKit if you can:
_es8388I2cWrite(10,0b00000000); // Use Lin1/Rin1 for ADC input (mic on LyraT)
//_es8388I2cWrite(10,0b01010000); // Use Lin2/Rin2 for ADC input (mic *and* line-in on AudioKit)
_es8388I2cWrite( 9,0b10001000); // Select Analog Input PGA Gain for ADC to +24dB (L+R)
_es8388I2cWrite(16,0b00000000); // Set ADC digital volume attenuation to 0dB (left)
_es8388I2cWrite(17,0b00000000); // Set ADC digital volume attenuation to 0dB (right)
_es8388I2cWrite(38,0b00011011); // Mixer - route LIN1/RIN1 to output after mic gain
_es8388I2cWrite(39,0b01000000); // Mixer - route LIN to mixL, +6dB gain
_es8388I2cWrite(42,0b01000000); // Mixer - route RIN to mixR, +6dB gain
_es8388I2cWrite(46,0b00100001); // LOUT1VOL - 0b00100001 = +4.5dB
_es8388I2cWrite(47,0b00100001); // ROUT1VOL - 0b00100001 = +4.5dB
_es8388I2cWrite(48,0b00100001); // LOUT2VOL - 0b00100001 = +4.5dB
_es8388I2cWrite(49,0b00100001); // ROUT2VOL - 0b00100001 = +4.5dB
// Music ALC - the mics like Auto Level Control
// You can also use this for line-in, but it's not really needed.
//
_es8388I2cWrite(18,0b11111000); // ALC: stereo, max gain +35.5dB, min gain -12dB
_es8388I2cWrite(19,0b00110000); // ALC: target -1.5dB, 0ms hold time
_es8388I2cWrite(20,0b10100110); // ALC: gain ramp up = 420ms/93ms, gain ramp down = check manual for calc
_es8388I2cWrite(21,0b00000110); // ALC: use "ALC" mode, no zero-cross, window 96 samples
_es8388I2cWrite(22,0b01011001); // ALC: noise gate threshold, PGA gain constant, noise gate enabled
#else
_es8388I2cWrite(10,0b01010000); // Use Lin2/Rin2 for ADC input ("line-in")
_es8388I2cWrite( 9,0b00000000); // Select Analog Input PGA Gain for ADC to 0dB (L+R)
_es8388I2cWrite(16,0b01000000); // Set ADC digital volume attenuation to -32dB (left)
_es8388I2cWrite(17,0b01000000); // Set ADC digital volume attenuation to -32dB (right)
_es8388I2cWrite(38,0b00001001); // Mixer - route LIN2/RIN2 to output
_es8388I2cWrite(39,0b01010000); // Mixer - route LIN to mixL, 0dB gain
_es8388I2cWrite(42,0b01010000); // Mixer - route RIN to mixR, 0dB gain
_es8388I2cWrite(46,0b00011011); // LOUT1VOL - 0b00011110 = +0dB, 0b00011011 = LyraT balance fix
_es8388I2cWrite(47,0b00011110); // ROUT1VOL - 0b00011110 = +0dB
_es8388I2cWrite(48,0b00011110); // LOUT2VOL - 0b00011110 = +0dB
_es8388I2cWrite(49,0b00011110); // ROUT2VOL - 0b00011110 = +0dB
#endif
}
public:
ES8388Source(SRate_t sampleRate, int blockSize, float sampleScale = 1.0f, bool i2sMaster=true) :
I2SSource(sampleRate, blockSize, sampleScale) {
_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
};
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
if ((i2sckPin < 0) || (mclkPin < 0)) {
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
return;
}
// First route mclk, then configure ADC over I2C, then configure I2S
_es8388InitAdc();
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
}
void deinitialize() {
I2SSource::deinitialize();
}
};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
#if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC)

View File

@ -85,8 +85,7 @@ class MPU6050Driver : public Usermod {
* setup() is called once at boot. WiFi is not yet connected at this point.
*/
void setup() {
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.setClock(400000U); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE

View File

@ -5,14 +5,18 @@
#ifndef MULTI_RELAY_MAX_RELAYS
#define MULTI_RELAY_MAX_RELAYS 4
#else
#if MULTI_RELAY_MAX_RELAYS>16
#if MULTI_RELAY_MAX_RELAYS>8
#undef MULTI_RELAY_MAX_RELAYS
#define MULTI_RELAY_MAX_RELAYS 16
#define MULTI_RELAY_MAX_RELAYS 8
#warning Maximum relays set to 8
#endif
#endif
#ifndef MULTI_RELAY_PINS
#define MULTI_RELAY_PINS -1
#define MULTI_RELAY_ENABLED false
#else
#define MULTI_RELAY_ENABLED true
#endif
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
@ -45,7 +49,7 @@ typedef struct relay_t {
int8_t pin;
struct { // reduces memory footprint
bool active : 1; // is the relay waiting to be switched
bool mode : 1; // does On mean 1 or 0 (inverted output)
bool invert : 1; // does On mean 1 or 0
bool state : 1; // 1 relay is On, 0 relay is Off
bool external : 1; // is the relay externally controlled
int8_t button : 4; // which button triggers relay
@ -315,7 +319,7 @@ int MultiRelay::getValue(String data, char separator, int index) {
//Write a byte to the IO expander
byte MultiRelay::IOexpanderWrite(byte address, byte _data ) {
Wire.beginTransmission(addrPcf8574 + address);
Wire.beginTransmission(address);
Wire.write(_data);
return Wire.endTransmission();
}
@ -323,7 +327,7 @@ byte MultiRelay::IOexpanderWrite(byte address, byte _data ) {
//Read a byte from the IO expander
byte MultiRelay::IOexpanderRead(int address) {
byte _data = 0;
Wire.requestFrom(addrPcf8574 + address, 1);
Wire.requestFrom(address, 1);
if (Wire.available()) {
_data = Wire.read();
}
@ -335,7 +339,7 @@ byte MultiRelay::IOexpanderRead(int address) {
MultiRelay::MultiRelay()
: _switchTimerStart(0)
, enabled(false)
, enabled(MULTI_RELAY_ENABLED)
, initDone(false)
, usePcf8574(USE_PCF8574)
, addrPcf8574(PCF8574_ADDRESS)
@ -347,7 +351,7 @@ MultiRelay::MultiRelay()
for (size_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
_relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1;
_relay[i].delay = 0;
_relay[i].mode = false;
_relay[i].invert = false;
_relay[i].active = false;
_relay[i].state = false;
_relay[i].external = false;
@ -359,25 +363,27 @@ MultiRelay::MultiRelay()
* switch relay on/off
*/
void MultiRelay::switchRelay(uint8_t relay, bool mode) {
if (relay>=MULTI_RELAY_MAX_RELAYS || (_relay[relay].pin<0 && !usePcf8574)) return;
if (relay>=MULTI_RELAY_MAX_RELAYS || _relay[relay].pin<0) return;
_relay[relay].state = mode;
if (usePcf8574) {
byte expander = relay/8;
uint16_t state = 0;
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) state |= (uint16_t)_relay[i].state << i; // fill relay states for all pins
state = (mode ? !_relay[relay].mode : _relay[relay].mode) ? state | (1<<relay) : state & ~(1<<relay); // take into account invert mode
IOexpanderWrite(expander, state>>(8*expander));
DEBUG_PRINT(F("PCF8574 Writing to ")); DEBUG_PRINT(addrPcf8574 + expander); DEBUG_PRINT(F(" with data ")); DEBUG_PRINTLN(state>>(8*expander));
} else {
if (usePcf8574 && _relay[relay].pin >= 100) {
// we need to send all ouputs at the same time
uint8_t state = 0;
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
if (_relay[i].pin < 100) continue;
uint8_t pin = _relay[i].pin - 100;
state |= (_relay[i].invert ? !_relay[i].state : _relay[i].state) << pin; // fill relay states for all pins
}
IOexpanderWrite(addrPcf8574, state);
DEBUG_PRINT(F("Writing to PCF8574: ")); DEBUG_PRINTLN(state);
} else if (_relay[relay].pin < 100) {
pinMode(_relay[relay].pin, OUTPUT);
digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
}
digitalWrite(_relay[relay].pin, _relay[relay].invert ? !_relay[relay].state : _relay[relay].state);
} else return;
publishMqtt(relay);
}
uint8_t MultiRelay::getActiveRelayCount() {
uint8_t count = 0;
if (usePcf8574) return MULTI_RELAY_MAX_RELAYS; // we don't know how many there are
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) if (_relay[i].pin>=0) count++;
return count;
}
@ -476,29 +482,28 @@ void MultiRelay::publishHomeAssistantAutodiscovery() {
void MultiRelay::setup() {
// pins retrieved from cfg.json (readFromConfig()) prior to running setup()
// if we want PCF8574 expander I2C pins need to be valid
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
if (i2c_sda<0 || i2c_scl<0) usePcf8574 = false;
if (usePcf8574) {
uint16_t state = 0;
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) state |= (uint16_t)(_relay[i].external ? (_relay[i].mode ? !_relay[i].state : _relay[i].state) : (_relay[i].mode ? !offMode : offMode)) << i; // fill relay states for all pins
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i += 8) {
byte expander = i/8;
IOexpanderWrite(expander, state>>(8*expander)); // init expander (set all outputs)
delay(1);
}
DEBUG_PRINTLN(F("PCF8574(s) inited."));
} else {
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
if (_relay[i].pin<0) continue;
if (!pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
_relay[i].pin = -1; // allocation failed
} else {
uint8_t state = 0;
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
if (usePcf8574 && _relay[i].pin >= 100) {
uint8_t pin = _relay[i].pin - 100;
if (!_relay[i].external) _relay[i].state = !offMode;
state |= (uint8_t)(_relay[i].invert ? !_relay[i].state : _relay[i].state) << pin;
} else if (_relay[i].pin<100 && _relay[i].pin>=0) {
if (pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
if (!_relay[i].external) _relay[i].state = !offMode;
switchRelay(i, _relay[i].state);
_relay[i].active = false;
} else {
_relay[i].pin = -1; // allocation failed
}
}
}
if (usePcf8574) {
IOexpanderWrite(addrPcf8574, state); // init expander (set all outputs)
DEBUG_PRINTLN(F("PCF8574(s) inited."));
}
_oldMode = offMode;
initDone = true;
}
@ -519,7 +524,7 @@ void MultiRelay::loop() {
_oldMode = offMode;
_switchTimerStart = millis();
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
if ((_relay[i].pin>=0 || usePcf8574) && !_relay[i].external) _relay[i].active = true;
if ((_relay[i].pin>=0) && !_relay[i].external) _relay[i].active = true;
}
}
@ -635,7 +640,7 @@ void MultiRelay::addToJsonInfo(JsonObject &root) {
String uiDomString;
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
if ((_relay[i].pin<0 && !usePcf8574) || !_relay[i].external) continue;
if (_relay[i].pin<0 || !_relay[i].external) continue;
uiDomString = F("Relay "); uiDomString += i;
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
@ -726,7 +731,7 @@ void MultiRelay::addToConfig(JsonObject &root) {
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
JsonObject relay = top.createNestedObject(parName);
relay["pin"] = _relay[i].pin;
relay[FPSTR(_activeHigh)] = _relay[i].mode;
relay[FPSTR(_activeHigh)] = _relay[i].invert;
relay[FPSTR(_delay_str)] = _relay[i].delay;
relay[FPSTR(_external)] = _relay[i].external;
relay[FPSTR(_button)] = _relay[i].button;
@ -735,9 +740,10 @@ void MultiRelay::addToConfig(JsonObject &root) {
}
void MultiRelay::appendConfigData() {
oappend(SET_F("addInfo('MultiRelay:first-PCF8574',1,'<i>(not hex!)</i>','address');"));
oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
//oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
}
/**
@ -762,7 +768,7 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
usePcf8574 = top[FPSTR(_pcf8574)] | usePcf8574;
addrPcf8574 = top[FPSTR(_pcfAddress)] | addrPcf8574;
// if I2C is not globally initialised just ignore
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
if (i2c_sda<0 || i2c_scl<0) usePcf8574 = false;
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
@ -771,14 +777,14 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
oldPin[i] = _relay[i].pin;
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
_relay[i].invert = top[parName][FPSTR(_activeHigh)] | _relay[i].invert;
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
_relay[i].button = top[parName][FPSTR(_button)] | _relay[i].button;
// begin backwards compatibility (beta) remove when 0.13 is released
parName += '-';
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
_relay[i].invert = top[parName+FPSTR(_activeHigh)] | _relay[i].invert;
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
// end compatibility
@ -792,22 +798,11 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
} else {
// deallocate all pins 1st
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++)
if (oldPin[i]>=0) {
if (oldPin[i]>=0 && oldPin[i]<100) {
pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
}
// allocate new pins
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
if (_relay[i].pin>=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) {
if (!_relay[i].external) {
_relay[i].state = !offMode;
switchRelay(i, _relay[i].state);
_oldMode = offMode;
}
} else {
_relay[i].pin = -1;
}
_relay[i].active = false;
}
setup();
DEBUG_PRINTLN(F(" config (re)loaded."));
}
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
@ -825,4 +820,4 @@ const char MultiRelay::_button[] PROGMEM = "button";
const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
const char MultiRelay::_pcf8574[] PROGMEM = "use-PCF8574";
const char MultiRelay::_pcfAddress[] PROGMEM = "first-PCF8574";
const char MultiRelay::_pcfAddress[] PROGMEM = "PCF8574-address";

View File

@ -16,7 +16,6 @@ class ShtUsermod : public Usermod
private:
bool enabled = false; // Is usermod enabled or not
bool firstRunDone = false; // Remembers if the first config load run had been done
bool pinAllocDone = true; // Remembers if we have allocated pins
bool initDone = false; // Remembers if the mod has been completely initialised
bool haMqttDiscovery = false; // Is MQTT discovery enabled or not
bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics
@ -94,7 +93,7 @@ void ShtUsermod::initShtTempHumiditySensor()
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
}
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
shtTempHumidSensor->begin(shtI2cAddress); // uses &Wire
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
cleanup();
@ -132,13 +131,6 @@ void ShtUsermod::cleanupShtTempHumiditySensor()
void ShtUsermod::cleanup()
{
cleanupShtTempHumiditySensor();
if (pinAllocDone) {
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
pinManager.deallocateMultiplePins(pins, 2, PinOwner::HW_I2C);
pinAllocDone = false;
}
enabled = false;
}
@ -237,14 +229,12 @@ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
void ShtUsermod::setup()
{
if (enabled) {
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
// GPIOs can be set to -1 and allocateMultiplePins() will return true, so check they're gt zero
if (i2c_sda < 0 || i2c_scl < 0 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) {
DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name);
// GPIOs can be set to -1 , so check they're gt zero
if (i2c_sda < 0 || i2c_scl < 0) {
DEBUG_PRINTF("[%s] I2C bus not initialised!\n", _name);
cleanup();
return;
}
pinAllocDone = true;
initShtTempHumiditySensor();

View File

@ -82,13 +82,14 @@ void DisplayTaskCode(void * parameter);
typedef enum {
NONE = 0,
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
SSD1306_SPI64, // U8X8_SSD1306_128X64_NONAME_HW_SPI
SSD1309_SPI64 // U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI
} DisplayType;
@ -533,24 +534,18 @@ void FourLineDisplayUsermod::sleepOrClock(bool enabled) {
// gets called once at boot. Do all initialization that doesn't depend on
// network here
void FourLineDisplayUsermod::setup() {
if (type == NONE || !enabled) return;
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64);
// check if pins are -1 and disable usermod as PinManager::allocateMultiplePins() will accept -1 as a valid pin
if (isSPI) {
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { type=NONE; return; }
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type=NONE; return; }
PinManagerPinType pins[2] = { { spi_sclk, true }, { spi_mosi, true } };
if (spi_sclk==-1 || spi_mosi==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_SPI)) {
pinManager.deallocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay);
if (spi_sclk<0 || spi_mosi<0 || ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) {
type = NONE;
return;
} else {
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type = NONE; }
}
} else {
PinManagerPinType pins[2] = { {i2c_scl, true }, { i2c_sda, true } };
if (i2c_scl==-1 || i2c_sda==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { type=NONE; return; }
if (i2c_scl<0 || i2c_sda<0) { type=NONE; }
}
DEBUG_PRINTLN(F("Allocating display."));
@ -563,20 +558,16 @@ void FourLineDisplayUsermod::setup() {
case SSD1305_64: u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(); break;
// U8X8 uses global SPI variable that is attached to VSPI bus on ESP32
case SSD1306_SPI: u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
case SSD1306_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
case SSD1306_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
case SSD1309_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
// catchall
default: u8x8 = (U8X8 *) new U8X8_NULL(); break;
default: u8x8 = (U8X8 *) new U8X8_NULL(); enabled = false; break; // catchall to create U8x8 instance
}
if (nullptr == u8x8) {
DEBUG_PRINTLN(F("Display init failed."));
if (isSPI) {
int8_t pins[] = {spi_sclk, spi_mosi};
pinManager.deallocateMultiplePins((const uint8_t*)pins, 2, PinOwner::HW_SPI);
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, 3, PinOwner::UM_FourLineDisplay);
} else {
int8_t pins[] = {i2c_scl, i2c_sda};
pinManager.deallocateMultiplePins((const uint8_t*)pins, 2, PinOwner::HW_I2C);
}
type = NONE;
return;
@ -1215,6 +1206,7 @@ void FourLineDisplayUsermod::appendConfigData() {
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);"));
oappend(SET_F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
@ -1306,38 +1298,30 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
bool pinsChanged = false;
for (byte i=0; i<3; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; }
if (pinsChanged || type!=newType) {
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64);
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64);
bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64 || newType == SSD1309_SPI64);
if (isSPI) {
if (pinsChanged || !newSPI) pinManager.deallocateMultiplePins((const uint8_t*)oldPin, 3, PinOwner::UM_FourLineDisplay);
if (!newSPI) {
// was SPI but is no longer SPI
int8_t oldPins[] = {spi_sclk, spi_mosi};
pinManager.deallocateMultiplePins((const uint8_t*)oldPins, 2, PinOwner::HW_SPI);
PinManagerPinType pins[2] = { {i2c_scl, true }, { i2c_sda, true } };
if (i2c_scl==-1 || i2c_sda==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { newType=NONE; }
if (i2c_scl<0 || i2c_sda<0) { newType=NONE; }
} else {
// still SPI but pins changed
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { newType=NONE; }
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
}
} else if (newSPI) {
// was I2C but is now SPI
int8_t oldPins[] = {i2c_scl, i2c_sda};
pinManager.deallocateMultiplePins((const uint8_t*)oldPins, 2, PinOwner::HW_I2C);
PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
else {
PinManagerPinType pins[2] = { { spi_sclk, true }, { spi_mosi, true } };
if (spi_sclk==-1 || spi_mosi==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_SPI)) {
pinManager.deallocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay);
newType = NONE;
}
if (spi_sclk<0 || spi_mosi<0) {
newType=NONE;
} else {
PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
}
} else {
// just I2C tye changed
// just I2C type changed
}
type = newType;
switch (type) {
@ -1369,8 +1353,12 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
break;
case SSD1309_SPI64:
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1309_128x64_noname0, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
default:
u8x8_Setup(u8x8->getU8x8(), u8x8_d_null_cb, u8x8_cad_empty, u8x8_byte_empty, u8x8_dummy_cb);
enabled = false;
break;
}
startDisplay();

View File

@ -45,6 +45,10 @@
#define ENCODER_SW_PIN 19
#endif
#ifndef ENCODER_MAX_DELAY_MS // max delay between polling encoder pins
#define ENCODER_MAX_DELAY_MS 8 // 8 milliseconds => max 120 change impulses in 1 second, for full turn of a 30/30 encoder (4 changes per segment, 30 segments for one turn)
#endif
#ifndef USERMOD_USE_PCF8574
#undef USE_PCF8574
#define USE_PCF8574 false
@ -343,7 +347,7 @@ class RotaryEncoderUIUsermod : public Usermod {
*/
void addToConfig(JsonObject &root);
//void appendConfigData();
void appendConfigData();
/**
* restore the changeable values
@ -376,6 +380,7 @@ class RotaryEncoderUIUsermod : public Usermod {
*/
byte RotaryEncoderUIUsermod::readPin(uint8_t pin) {
if (usePcf8574) {
if (pin >= 100) pin -= 100; // PCF I/O ports
return (pcfPortData>>pin) & 1;
} else {
return digitalRead(pin);
@ -473,7 +478,7 @@ void RotaryEncoderUIUsermod::setup()
DEBUG_PRINTLN(F("Usermod Rotary Encoder init."));
if (usePcf8574) {
if ((i2c_sda == i2c_scl && i2c_sda == -1) || pinA<0 || pinB<0 || pinC<0) {
if (i2c_sda < 0 || i2c_scl < 0 || pinA < 0 || pinB < 0 || pinC < 0) {
DEBUG_PRINTLN(F("I2C and/or PCF8574 pins unused, disabling."));
enabled = false;
return;
@ -538,8 +543,9 @@ void RotaryEncoderUIUsermod::setup()
*/
void RotaryEncoderUIUsermod::loop()
{
if (!enabled || strip.isUpdating()) return;
if (!enabled) return;
unsigned long currentTime = millis(); // get the current elapsed time
if (strip.isUpdating() && ((currentTime - loopTime) < ENCODER_MAX_DELAY_MS)) return; // be nice, but not too nice
// Initialize effectCurrentIndex and effectPaletteIndex to
// current state. We do it here as (at least) effectCurrent
@ -1071,9 +1077,10 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) {
DEBUG_PRINTLN(F("Rotary Encoder config saved."));
}
//void RotaryEncoderUIUsermod::appendConfigData() {
// oappend(SET_F("addInfo('RotaryEncoderUIUsermod:PCF8574-address',1,'<i>(not hex!)</i>');"));
//}
void RotaryEncoderUIUsermod::appendConfigData() {
oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'<i>(not hex!)</i>');"));
oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
}
/**
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
@ -1122,7 +1129,7 @@ bool RotaryEncoderUIUsermod::readFromConfig(JsonObject &root) {
pinManager.deallocatePin(pinIRQ, PinOwner::UM_RotaryEncoderUI);
DEBUG_PRINTLN(F("Deallocated old IRQ pin."));
}
pinIRQ = newIRQpin;
pinIRQ = newIRQpin<100 ? newIRQpin : -1; // ignore PCF8574 pins
} else {
pinManager.deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI);
pinManager.deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI);

View File

@ -1,25 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2046
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wled00", "wled00\wled00.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9A679C2B-61D3-400B-B96F-06E604E9CED2}
EndGlobalSection
EndGlobal

View File

@ -278,7 +278,7 @@ uint16_t mode_random_color(void) {
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), fade));
return FRAMETIME;
}
static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!";
static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!;01";
/*
@ -433,7 +433,7 @@ uint16_t mode_rainbow(void) {
return FRAMETIME;
}
static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!";
static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!;01";
/*
@ -5095,21 +5095,22 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
const uint16_t rows = SEGMENT.virtualHeight();
SEGMENT.fadeToBlackBy(SEGMENT.intensity);
uint_fast16_t phase = (millis() * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed
//for (int i=0; i < 4*(cols+rows); i ++) {
for (int i=0; i < 256; i ++) {
//float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f;
//float ylocn = float(cos8(now/4+i*2)) / 255.0f;
uint8_t xlocn = sin8(millis()/4+i*(SEGMENT.speed>>5));
uint8_t ylocn = cos8(millis()/4+i*2);
xlocn = map(xlocn,0,255,0,cols-1);
ylocn = map(ylocn,0,255,0,rows-1);
SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/32);
uint_fast8_t ylocn = cos8(phase/2 + i*2);
xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding
ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map()
SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
}
return FRAMETIME;
} // mode_2DLissajous()
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate;!;!;2";
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,,,Speed;!;!;2;;c3=15";
///////////////////////
@ -5273,7 +5274,7 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito
SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2);
float t = millis() / (33 - SEGMENT.speed/8);
uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float
for (int i = 0; i < cols; i++) {
uint16_t thisVal = inoise8(i * 30, t, t);
uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1);
@ -5876,11 +5877,17 @@ uint16_t mode_2Dscrollingtext(void) {
case 4: letterWidth = 7; letterHeight = 9; break;
case 5: letterWidth = 5; letterHeight = 12; break;
}
const bool zero = SEGMENT.check3;
const int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-letterHeight)/2;
char text[33] = {'\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 (!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
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];
byte AmPmHour = hour(localTime);
boolean isitAM = true;
@ -5890,12 +5897,12 @@ uint16_t mode_2Dscrollingtext(void) {
}
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, PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, PSTR("%d.%d"), day(localTime), month(localTime));
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, PSTR("%d/%d"), month(localTime), day(localTime));
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, PSTR("%2d:%02d"), AmPmHour, minute(localTime));
else sprintf_P(text, PSTR("%s %d, %d %2d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
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);
@ -5922,7 +5929,7 @@ uint16_t mode_2Dscrollingtext(void) {
return FRAMETIME;
}
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,,Gradient,Overlay;!,!,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,,Gradient,Overlay,0;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";
////////////////////////////
@ -6833,7 +6840,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
return FRAMETIME;
} // mode_freqmatrix()
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Time delay,Sound effect,Low bin,High bin,Sensivity;;;1f;m12=3,si=0"; // Corner, Beatsin
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensivity;;;1f;m12=3,si=0"; // Corner, Beatsin
//////////////////////
@ -6937,7 +6944,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
return FRAMETIME;
} // mode_freqwave()
static const char _data_FX_MODE_FREQWAVE[] PROGMEM = "Freqwave@Time delay,Sound effect,Low bin,High bin,Pre-amp;;;1f;m12=2,si=0"; // Circle, Beatsin
static const char _data_FX_MODE_FREQWAVE[] PROGMEM = "Freqwave@Speed,Sound effect,Low bin,High bin,Pre-amp;;;1f;m12=2,si=0"; // Circle, Beatsin
///////////////////////

View File

@ -487,7 +487,7 @@ typedef struct Segment {
//if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB));
//Serial.println();
//#endif
if (!Segment::_globalLeds && leds) free(leds);
if (!Segment::_globalLeds && leds) { free(leds); leds = nullptr;} // reset to nullptr, to avoid race conditions
if (name) delete[] name;
if (_t) delete _t;
deallocateData();
@ -507,9 +507,9 @@ typedef struct Segment {
inline bool hasRGB(void) const { return _isRGB; }
inline bool hasWhite(void) const { return _hasW; }
inline bool isCCT(void) const { return _isCCT; }
inline uint16_t width(void) const { return stop - start; } // segment width in physical pixels (length if 1D)
inline uint16_t height(void) const { return stopY - startY; } // segment height (if 2D) in physical pixels
inline uint16_t length(void) const { return width() * height(); } // segment length (count) in physical pixels
inline uint16_t width(void) const { return (stop > start) ? (stop - start) : 0; } // segment width in physical pixels (length if 1D)
inline uint16_t height(void) const { return (stopY > startY) ? (stopY - startY) : 0; } // segment height (if 2D) in physical pixels // softhack007: make sure its always > 0
inline uint16_t length(void) const { return width() * height(); } // segment length (count) in physical pixels
inline uint16_t groupLength(void) const { return grouping + spacing; }
inline uint8_t getLightCapabilities(void) const { return _capabilities; }
@ -710,7 +710,7 @@ class WS2812FX { // 96 bytes
panel.clear();
#endif
customPalettes.clear();
if (useLedsArray && Segment::_globalLeds) free(Segment::_globalLeds);
if (useLedsArray && Segment::_globalLeds) {free(Segment::_globalLeds); Segment::_globalLeds = nullptr;} // reset to nullptr, to avoid race conditions
}
static WS2812FX* getInstance(void) { return instance; }

View File

@ -191,6 +191,8 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) {
uint16_t width = virtualWidth(); // segment width in logical pixels
uint16_t height = virtualHeight(); // segment height in logical pixels
if (width == 0) return 0; // softhack007 avoid div/0
if (height == 0) return (x%width); // softhack007 avoid div/0
return (x%width) + (y%height) * width;
}
@ -202,7 +204,6 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
if (leds) leds[XY(x,y)] = col;
uint8_t _bri_t = currentBri(on ? opacity : 0);
if (!_bri_t && !transitional) return;
if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t);
@ -305,6 +306,7 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t
// Adds the specified color with the existing pixel color perserving color balance.
void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
uint32_t col = getPixelColorXY(x,y);
uint8_t r = R(col);
uint8_t g = G(col);
@ -329,50 +331,54 @@ void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
// blurRow: perform a blur on a row of a rectangular matrix
void Segment::blurRow(uint16_t row, fract8 blur_amount) {
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
if (row >= rows) return;
// blur one row
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for (uint16_t x = 0; x < cols; x++) {
for (uint_fast16_t x = 0; x < cols; x++) {
CRGB cur = getPixelColorXY(x, row);
CRGB before = cur; // remember color before blur
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (x) {
if (x>0) {
CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part;
setPixelColorXY(x-1, row, prev);
}
setPixelColorXY(x, row, cur);
if (before != cur) // optimization: only set pixel if color has changed
setPixelColorXY(x, row, cur);
carryover = part;
}
}
// blurCol: perform a blur on a column of a rectangular matrix
void Segment::blurCol(uint16_t col, fract8 blur_amount) {
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
if (col >= cols) return;
// blur one column
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for (uint16_t i = 0; i < rows; i++) {
CRGB cur = getPixelColorXY(col, i);
for (uint_fast16_t y = 0; y < rows; y++) {
CRGB cur = getPixelColorXY(col, y);
CRGB part = cur;
CRGB before = cur; // remember color before blur
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (i) {
CRGB prev = CRGB(getPixelColorXY(col, i-1)) + part;
setPixelColorXY(col, i-1, prev);
if (y>0) {
CRGB prev = CRGB(getPixelColorXY(col, y-1)) + part;
setPixelColorXY(col, y-1, prev);
}
setPixelColorXY(col, i, cur);
if (before != cur) // optimization: only set pixel if color has changed
setPixelColorXY(col, y, cur);
carryover = part;
}
}
@ -391,8 +397,8 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
for (uint16_t j = 0; j < dim1; j++) {
uint16_t x = vertical ? i : j;
uint16_t y = vertical ? j : i;
uint16_t xp = vertical ? x : x-1;
uint16_t yp = vertical ? y-1 : y;
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
int16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow
uint16_t xn = vertical ? x : x+1;
uint16_t yn = vertical ? y+1 : y;
CRGB curr = getPixelColorXY(x,y);

View File

@ -90,18 +90,18 @@ Segment::Segment(const Segment &orig) {
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._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
if (orig.leds && !Segment::_globalLeds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
if (orig.leds && !Segment::_globalLeds && length() > 0) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
}
// move constructor
Segment::Segment(Segment &&orig) noexcept {
//DEBUG_PRINTLN(F("-- Move segment constructor --"));
memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.leds = nullptr;
orig.name = nullptr;
orig.data = nullptr;
orig._dataLen = 0;
orig._t = nullptr;
orig.leds = nullptr;
}
// copy assignment
@ -111,7 +111,7 @@ Segment& Segment::operator= (const Segment &orig) {
// clean destination
if (name) delete[] name;
if (_t) delete _t;
if (leds && !Segment::_globalLeds) free(leds);
if (leds && !Segment::_globalLeds) {free(leds); leds=nullptr;}
deallocateData();
// copy source
memcpy((void*)this, (void*)&orig, sizeof(Segment));
@ -125,7 +125,7 @@ Segment& Segment::operator= (const Segment &orig) {
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._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
if (orig.leds && !Segment::_globalLeds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
if (orig.leds && !Segment::_globalLeds && length() > 0) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
}
return *this;
}
@ -137,7 +137,7 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
if (name) delete[] name; // free old name
deallocateData(); // free old runtime data
if (_t) delete _t;
if (leds && !Segment::_globalLeds) free(leds);
if (leds && !Segment::_globalLeds) {free(leds); leds=nullptr;}
memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.name = nullptr;
orig.data = nullptr;
@ -305,23 +305,26 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
}
void Segment::startTransition(uint16_t dur) {
if (transitional || _t) return; // already in transition no need to store anything
if (!dur) {
transitional = false;
if (_t) {
delete _t;
_t = nullptr;
}
return;
}
if (transitional && _t) return; // already in transition no need to store anything
// starting a transition has to occur before change so we get current values 1st
uint8_t _briT = currentBri(on ? opacity : 0);
uint8_t _cctT = currentBri(cct, true);
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
uint8_t _modeP = mode;
uint32_t _colorT[NUM_COLORS];
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = currentColor(i, colors[i]);
if (!_t) _t = new Transition(dur); // no previous transition running
_t = new Transition(dur); // no previous transition running
if (!_t) return; // failed to allocate data
_t->_briT = _briT;
_t->_cctT = _cctT;
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
_t->_briT = on ? opacity : 0;
_t->_cctT = cct;
_t->_palT = _palT;
_t->_modeP = _modeP;
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = _colorT[i];
_t->_modeP = mode;
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
}
@ -334,10 +337,10 @@ uint16_t Segment::progress() {
}
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
if (transitional && _t) {
uint32_t prog = progress() + 1;
if (useCct) return ((briNew * prog) + _t->_cctT * (0x10000 - prog)) >> 16;
else return ((briNew * prog) + _t->_briT * (0x10000 - prog)) >> 16;
uint32_t prog = progress();
if (transitional && _t && prog < 0xFFFFU) {
if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16;
else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16;
} else {
return briNew;
}
@ -368,6 +371,7 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal
void Segment::handleTransition() {
if (!transitional) return;
uint16_t _progress = progress();
if (_progress == 0xFFFFU) transitional = false; // finish transitioning segment
if (_t) { // thanks to @nXm AKA https://github.com/NMeirer
if (_progress >= 32767U && _t->_modeP != mode) markForReset();
if (_progress == 0xFFFFU) {
@ -375,7 +379,6 @@ void Segment::handleTransition() {
_t = nullptr;
}
}
if (_progress == 0xFFFFU) transitional = false; // finish transitioning segment
}
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
@ -544,6 +547,7 @@ uint16_t Segment::virtualLength() const {
}
#endif
uint16_t groupLen = groupLength();
if (groupLen < 1) groupLen = 1; // prevent division by zero - better safe than sorry ...
uint16_t vLength = (length() + groupLen - 1) / groupLen;
if (mirror) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vLength;
@ -622,7 +626,6 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
uint16_t len = length();
uint8_t _bri_t = currentBri(on ? opacity : 0);
if (!_bri_t && !transitional && fadeTransition) return; // if _bri_t == 0 && segment is not transitionig && transitions are enabled then save a few CPU cycles
if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t);
@ -727,7 +730,7 @@ uint32_t Segment::getPixelColor(int i)
i += start;
/* offset/phase */
i += offset;
if (i >= stop) i -= length();
if ((i >= stop) && (stop>0)) i -= length(); // avoids negative pixel index (stop = 0 is a possible value)
return strip.getPixelColor(i);
}
@ -884,6 +887,7 @@ void Segment::fade_out(uint8_t rate) {
// fades all pixels to black using nscale8()
void Segment::fadeToBlackBy(uint8_t fadeBy) {
if (fadeBy == 0) return; // optimization - no scaling to apply
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
const uint16_t rows = virtualHeight(); // will be 1 for 1D
@ -898,23 +902,26 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
*/
void Segment::blur(uint8_t blur_amount)
{
if (blur_amount == 0) return; // optimization: 0 means "don't blur"
#ifndef WLED_DISABLE_2D
if (is2D()) {
// compatibility with 2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (uint16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
for (uint16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
for (uint_fast16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
for (uint_fast16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
return;
}
#endif
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for(uint16_t i = 0; i < virtualLength(); i++)
uint_fast16_t vlength = virtualLength();
for(uint_fast16_t i = 0; i < vlength; i++)
{
CRGB cur = CRGB(getPixelColor(i));
CRGB part = cur;
CRGB before = cur; // remember color before blur
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
@ -923,9 +930,10 @@ void Segment::blur(uint8_t blur_amount)
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
}
setPixelColor(i,cur.red, cur.green, cur.blue);
if (before != cur) // optimization: only set pixel if color has changed
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue);
carryover = part;
}
}
@ -1075,7 +1083,7 @@ void WS2812FX::finalizeInit(void)
//else
//#endif
Segment::_globalLeds = (CRGB*) malloc(arrSize);
memset(Segment::_globalLeds, 0, arrSize);
if (Segment::_globalLeds && (arrSize > 0)) memset(Segment::_globalLeds, 0, arrSize);
}
//segments are created in makeAutoSegments();
@ -1220,7 +1228,8 @@ void WS2812FX::estimateCurrentAndLimitBri() {
}
uint32_t powerSum0 = powerSum;
powerSum *= _brightness;
//powerSum *= _brightness; // for NPBrightnessBus
powerSum *= 255; // no need to scale down powerSum - NPB-LG getPixelColor returns colors scaled down by brightness
if (powerSum > powerBudget) //scale brightness down to stay in current limit
{
@ -1228,11 +1237,14 @@ void WS2812FX::estimateCurrentAndLimitBri() {
uint16_t scaleI = scale * 255;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
uint8_t newBri = scale8(_brightness, scaleB);
busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
// to keep brightness uniform, sets virtual busses too - softhack007: apply reductions immediately
if (scaleB < 255) busses.setBrightness(scaleB, true); // NPB-LG has already applied brightness, so its suffifient to post-apply scaling ==> use scaleB instead of newBri
busses.setBrightness(newBri, false); // set new brightness for next frame
//currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; // for NPBrightnessBus
currentMilliamps = (powerSum0 * scaleB) / puPerMilliamp; // for NPBus-LG
} else {
currentMilliamps = powerSum / puPerMilliamp;
busses.setBrightness(_brightness);
busses.setBrightness(_brightness, false); // set new brightness for next frame
}
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
currentMilliamps += pLen; //add standby power back to estimate
@ -1590,7 +1602,7 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) {
}
void WS2812FX::setTransitionMode(bool t) {
for (segment &seg : _segments) if (!seg.transitional) seg.startTransition(t ? _transitionDur : 0);
for (segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0);
}
#ifdef WLED_DEBUG

View File

@ -9,9 +9,9 @@
#include <IPAddress.h>
#define NODE_TYPE_ID_UNDEFINED 0
#define NODE_TYPE_ID_ESP8266 82
#define NODE_TYPE_ID_ESP32 32
#define NODE_TYPE_ID_ESP32S2 33
#define NODE_TYPE_ID_ESP8266 82 // should be 1
#define NODE_TYPE_ID_ESP32 32 // should be 2
#define NODE_TYPE_ID_ESP32S2 33 // etc
#define NODE_TYPE_ID_ESP32S3 34
#define NODE_TYPE_ID_ESP32C3 35
@ -23,7 +23,13 @@ struct NodeStruct
String nodeName;
IPAddress ip;
uint8_t age;
uint8_t nodeType;
union {
uint8_t nodeType; // a waste of space as we only have 5 types
struct {
uint8_t type : 7; // still a waste of space (4 bits would be enough and future-proof)
bool on : 1;
};
};
uint32_t build;
NodeStruct() : age(0), nodeType(0), build(0)

View File

@ -126,15 +126,15 @@ bool BusDigital::canShow() {
return PolyBus::canShow(_busPtr, _iType);
}
void BusDigital::setBrightness(uint8_t b) {
void BusDigital::setBrightness(uint8_t b, bool immediate) {
//Fix for turning off onboard LED breaking bus
#ifdef LED_BUILTIN
if (_bri == 0 && b > 0) {
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
}
#endif
Bus::setBrightness(b);
PolyBus::setBrightness(_busPtr, _iType, b);
Bus::setBrightness(b, immediate);
PolyBus::setBrightness(_busPtr, _iType, b, immediate);
}
//If LEDs are skipped, it is possible to use the first as a status LED.
@ -515,9 +515,9 @@ void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct)
}
}
void BusManager::setBrightness(uint8_t b) {
void BusManager::setBrightness(uint8_t b, bool immediate) {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->setBrightness(b);
busses[i]->setBrightness(b, immediate);
}
}

View File

@ -108,7 +108,7 @@ class Bus {
virtual void setStatusPixel(uint32_t c) {}
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
virtual uint32_t getPixelColor(uint16_t pix) { return 0; }
virtual void setBrightness(uint8_t b) { _bri = b; };
virtual void setBrightness(uint8_t b, bool immediate=false) { _bri = b; };
virtual void cleanup() = 0;
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
virtual uint16_t getLength() { return _len; }
@ -181,7 +181,7 @@ class BusDigital : public Bus {
bool canShow();
void setBrightness(uint8_t b);
void setBrightness(uint8_t b, bool immediate);
void setStatusPixel(uint32_t c);
@ -345,7 +345,7 @@ class BusManager {
void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
void setBrightness(uint8_t b);
void setBrightness(uint8_t b, bool immediate=false); // immediate=true is for use in ABL, it applies brightness immediately (warning: inefficient)
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);

View File

@ -806,101 +806,101 @@ class PolyBus {
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
}
};
static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) {
static void setBrightness(void* busPtr, uint8_t busType, uint8_t b, bool immediate) { // immediate=true is for use in ABL, it applies brightness immediately (warning: inefficient)
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetLuminance(b); break;
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetLuminance(b); break;
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetLuminance(b); break;
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetLuminance(b); break;
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->SetLuminance(b); break;
case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->SetLuminance(b); break;
case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetLuminance(b); break;
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetLuminance(b); break;
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_400_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetLuminance(b); break;
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetLuminance(b); break;
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetLuminance(b); break;
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetLuminance(b); break;
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); break;
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetLuminance(b); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetLuminance(b); break;
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetLuminance(b); break;
case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->SetLuminance(b); break;
case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->SetLuminance(b); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetLuminance(b); break;
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetLuminance(b); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); break;
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
}
};
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {

View File

@ -197,6 +197,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
disablePullUp = !pull;
JsonArray hw_btn_ins = btn_obj[F("ins")];
if (!hw_btn_ins.isNull()) {
for (uint8_t b = 0; b < WLED_MAX_BUTTONS; b++) { // deallocate existing button pins
pinManager.deallocatePin(btnPin[b], PinOwner::Button); // does nothing if trying to deallocate a pin with PinOwner != Button
}
uint8_t s = 0;
for (JsonObject btn : hw_btn_ins) {
CJSON(buttonType[s], btn["type"]);
@ -264,6 +267,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
if (hw_ir_pin > -2) {
pinManager.deallocatePin(irPin, PinOwner::IR);
if (pinManager.allocatePin(hw_ir_pin, false, PinOwner::IR)) {
irPin = hw_ir_pin;
} else {
@ -276,6 +280,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject relay = hw[F("relay")];
int hw_relay_pin = relay["pin"] | -2;
if (hw_relay_pin > -2) {
pinManager.deallocatePin(rlyPin, PinOwner::Relay);
if (pinManager.allocatePin(hw_relay_pin,true, PinOwner::Relay)) {
rlyPin = hw_relay_pin;
pinMode(rlyPin, OUTPUT);
@ -443,6 +448,13 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(retainMqttMsg, if_mqtt[F("rtn")]);
#endif
#ifndef WLED_DISABLE_ESPNOW
JsonObject remote = doc["remote"];
CJSON(enable_espnow_remote, remote[F("remote_enabled")]);
getStringFromJson(linked_remote, remote[F("linked_remote")], 13);
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces["hue"];
CJSON(huePollingEnabled, if_hue["en"]);
@ -895,6 +907,13 @@ void serializeConfig() {
if_mqtt_topics[F("group")] = mqttGroupTopic;
#endif
#ifndef WLED_DISABLE_ESPNOW
JsonObject remote = doc.createNestedObject(F("remote"));
remote[F("remote_enabled")] = enable_espnow_remote;
remote[F("linked_remote")] = linked_remote;
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue["en"] = huePollingEnabled;

View File

@ -91,6 +91,21 @@
#endif
#endif
#ifndef WLED_MAX_SEGNAME_LEN
#ifdef ESP8266
#define WLED_MAX_SEGNAME_LEN 32
#else
#define WLED_MAX_SEGNAME_LEN 64
#endif
#else
#if WLED_MAX_SEGNAME_LEN<32
#undef WLED_MAX_SEGNAME_LEN
#define WLED_MAX_SEGNAME_LEN 32
#else
#warning WLED UI does not support modified maximum segment name length!
#endif
#endif
//Usermod IDs
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
@ -333,12 +348,29 @@
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
//Timer mode types
// Timer mode types
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
#define NL_MODE_FADE 1 //Fade to target brightness gradually
#define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color gradually
#define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min.
// Settings sub page IDs
#define SUBPAGE_MENU 0
#define SUBPAGE_WIFI 1
#define SUBPAGE_LEDS 2
#define SUBPAGE_UI 3
#define SUBPAGE_SYNC 4
#define SUBPAGE_TIME 5
#define SUBPAGE_SEC 6
#define SUBPAGE_DMX 7
#define SUBPAGE_UM 8
#define SUBPAGE_UPDATE 9
#define SUBPAGE_2D 10
#define SUBPAGE_LOCK 251
#define SUBPAGE_PINREQ 252
#define SUBPAGE_CSS 253
#define SUBPAGE_JS 254
#define SUBPAGE_WELCOME 255
#define NTP_PACKET_SIZE 48
@ -371,7 +403,7 @@
#ifdef ESP8266
#define SETTINGS_STACK_BUF_SIZE 2048
#else
#define SETTINGS_STACK_BUF_SIZE 3096
#define SETTINGS_STACK_BUF_SIZE 3608 // warning: quite a large value for stack
#endif
#ifdef WLED_USE_ETHERNET
@ -443,7 +475,10 @@
#define DEFAULT_LED_COUNT 30
#endif
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
#define INTERFACE_UPDATE_COOLDOWN 1000 // time in ms to wait between websockets, alexa, and MQTT updates
#define PIN_RETRY_COOLDOWN 3000 // time in ms after an incorrect attempt PIN and OTA pass will be rejected even if correct
#define PIN_TIMEOUT 900000 // time in ms after which the PIN will be required again, 15 minutes
// HW_PIN_SCL & HW_PIN_SDA are used for information in usermods settings page and usermods themselves
// which GPIO pins are actually used in a hardwarea layout (controller board)

View File

@ -42,6 +42,6 @@
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAbUExURQAAAAB81gCU/zKq/////9bW1oCAgGhoaAAAAGPLX8AAAAAJdFJOU///////////AFNPeBIAAAAJcEhZcwAADsAAAA7AAWrWiQkAAACdSURBVDhPxc9bDoUgEANQebP/FUuHMjBGY/B+3EYR7RH0qC/ZBc6HwCljgHO+xZIVSI2sYgHaG7EBWh8jWoxTrCBFdDJ+BD4lbIHxAcz8APAVLTsrZE4eQD5qzt3cAFTYokC4YCN9Gybgu4yAQtBFLQXHuHABA7JMeOEC/E0W5uy9gv4vo5QHK2i7yq2C8UABM4HmL+CSTXCTF1DrCX6+Gp9zB5dsAAAAAElFTkSuQmCC">
<h1>404 Not Found</h1>
<b>Akemi does not know where you are headed...</b><br><br>
<button onclick="window.location.href='../sliders'">Back to controls</button>
<button onclick="window.location.href='../?sliders'">Back to controls</button>
</body>
</html>

View File

@ -134,7 +134,7 @@ button {
.off {
color: var(--c-6) !important;
cursor: default !important;
/* cursor: default !important; */
}
.top .icons, .bot .icons {
@ -1024,7 +1024,7 @@ textarea {
width: 50px !important;
}
.segname, .pname {
.segname, .pname, .bname {
white-space: nowrap;
text-align: center;
overflow: hidden;
@ -1034,6 +1034,9 @@ textarea {
max-width: 170px;
position: relative;
}
.bname {
padding: 0 24px;
}
.segname .flr, .pname .flr {
transform: rotate(0deg);

View File

@ -380,8 +380,8 @@
</div>
</div>
<div id="mliveview2D" class="modal">
<div id="kliveview2D" style="width:100%; height:100%">Loading...</div><br>
<div id="mlv2D" class="modal">
<div id="klv2D" style="width:100%; height:100%">Loading...</div>
</div>
<div id="rover" class="modal">

View File

@ -22,11 +22,12 @@ var pN = "", pI = 0, pNum = 0;
var pmt = 1, pmtLS = 0, pmtLast = 0;
var lastinfo = {};
var isM = false, mw = 0, mh=0;
var ws, cpick, ranges;
var ws, cpick, ranges, wsRpt=0;
var cfg = {
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false, css:true, hdays:false, pxm: false}
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false,
css:true, hdays:false, fxdef:true, pxm: false}
};
var hol = [
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
@ -219,6 +220,7 @@ function onLoad()
// detect reverse proxy and/or HTTPS
let pathn = l.pathname;
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
//if (paths[0]==="sliders") paths.shift();
//while (paths[0]==="") paths.shift();
locproto = l.protocol;
locip = l.hostname + (l.port ? ":" + l.port : "");
@ -776,7 +778,7 @@ function populateSegments(s)
`<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})">&#xe395;</i>`+
(cfg.comp.segpwr ? segp : '') +
`<div class="segin" id="seg${i}in">`+
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=${li.arch=="esp8266"?32:64} value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
`<table class="infot segt">`+
`<tr>`+
`<td>${isMSeg?'Start X':'Start LED'}</td>`+
@ -829,6 +831,7 @@ function populateSegments(s)
resetUtil(noNewSegs);
if (gId('selall')) gId('selall').checked = true;
for (var i = 0; i <= lSeg; i++) {
if (!gId(`seg${i}`)) continue;
updateLen(i);
updateTrail(gId(`seg${i}bri`));
gId(`segr${i}`).classList.add("hide");
@ -1007,10 +1010,15 @@ function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', e
function btype(b)
{
switch (b) {
case 2:
case 32: return "ESP32";
case 3:
case 33: return "ESP32-S2";
case 4:
case 34: return "ESP32-S3";
case 5:
case 35: return "ESP32-C3";
case 1:
case 82: return "ESP8266";
}
return "?";
@ -1031,8 +1039,9 @@ function populateNodes(i,n)
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
for (var o of n.nodes) {
if (o.name) {
var url = `<button class="btn" title="${o.ip}" onclick="location.assign('http://${o.ip}');">${bname(o)}</button>`;
urows += inforow(url,`${btype(o.type)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
let onoff = `<i class="icons e-icon flr ${o.type&0x80?'':'off'}" onclick="rmtTgl('${o.ip}',this);"">&#xe08f;</i>`;
var url = `<button class="btn" title="${o.ip}" onclick="location.assign('http://${o.ip}');"><div class="bname">${bname(o)}</div>${o.vid<2307130?'':onoff}</button>`;
urows += inforow(url,`${btype(o.type&0x7F)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
nnodes++;
}
}
@ -1334,11 +1343,12 @@ function makeWS() {
};
ws.onclose = (e)=>{
gId('connind').style.backgroundColor = "var(--c-r)";
setTimeout(makeWS,1500); // retry WS connection
if (wsRpt++ < 5) setTimeout(makeWS,1500); // retry WS connection
ws = null;
}
ws.onopen = (e)=>{
//ws.send("{'v':true}"); // unnecessary (https://github.com/Aircoookie/WLED/blob/master/wled00/ws.cpp#L18)
wsRpt = 0;
reqsLegal = true;
}
}
@ -1640,6 +1650,7 @@ function requestJson(command=null)
//load presets and open websocket sequentially
if (!pJson || isEmpty(pJson)) setTimeout(()=>{
loadPresets(()=>{
wsRpt = 0;
if (!(ws && ws.readyState === WebSocket.OPEN)) makeWS();
});
},25);
@ -1687,28 +1698,23 @@ function toggleSync()
function toggleLiveview()
{
//WLEDSR adding liveview2D support
if (isInfo && isM) toggleInfo();
if (isNodes && isM) toggleNodes();
if (isPXM && isM) togglePixelMagicTool();
isLv = !isLv;
let wsOn = ws && ws.readyState === WebSocket.OPEN;
var lvID = "liveview";
if (isM) {
lvID = "liveview2D"
if (isLv) {
var cn = '<iframe id="liveview2D" src="about:blank"></iframe>';
d.getElementById('kliveview2D').innerHTML = cn;
}
gId('mliveview2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
if (isM && wsOn) {
lvID += "2D";
if (isLv) gId('klv2D').innerHTML = `<iframe id="${lvID}" src="about:blank"></iframe>`;
gId('mlv2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
}
gId(lvID).style.display = (isLv) ? "block":"none";
var url = getURL("/" + lvID);
gId(lvID).src = (isLv) ? url:"about:blank";
gId('buttonSr').className = (isLv) ? "active":"";
if (!isLv && ws && ws.readyState === WebSocket.OPEN) ws.send('{"lv":false}');
gId(lvID).src = (isLv) ? getURL("/" + lvID + ((wsOn) ? "?ws":"")):"about:blank";
gId('buttonSr').classList.toggle("active");
if (!isLv && wsOn) ws.send('{"lv":false}');
size();
}
@ -2088,14 +2094,14 @@ function tglSegn(s)
function selSegAll(o)
{
var obj = {"seg":[]};
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":o.checked});
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":o.checked});
requestJson(obj);
}
function selSegEx(s)
{
var obj = {"seg":[]};
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":(i==s)});
obj.mainseg = s;
requestJson(obj);
}
@ -2113,7 +2119,7 @@ function selGrp(g)
event.stopPropagation();
var sel = gId(`segcont`).querySelectorAll(`div[data-set="${g}"]`);
var obj = {"seg":[]};
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":false});
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":false});
if (sel) for (let s of sel||[]) {
let i = parseInt(s.id.substring(3));
obj.seg[i] = {"id":i,"sel":true};
@ -2280,8 +2286,7 @@ function setFX(ind = null)
} else {
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
}
var obj = {"seg": {"fx": parseInt(ind),"fxdef":1}}; // fxdef sets effect parameters to default values, TODO add client setting
var obj = {"seg": {"fx": parseInt(ind), "fxdef": cfg.comp.fxdef}}; // fxdef sets effect parameters to default values
requestJson(obj);
}
@ -2615,6 +2620,24 @@ function setBalance(b)
requestJson(obj);
}
function rmtTgl(ip,i) {
event.preventDefault();
event.stopPropagation();
fetch(`http://${ip}/win&T=2`, {method: 'get'})
.then((r)=>{
return r.text();
})
.then((t)=>{
let c = (new window.DOMParser()).parseFromString(t, "text/xml");
// perhaps just i.classList.toggle("off"); would be enough
if (c.getElementsByTagName('ac')[0].textContent === "0") {
i.classList.add("off");
} else {
i.classList.remove("off");
}
});
}
var hc = 0;
setInterval(()=>{
if (!isInfo) return;

View File

@ -17,14 +17,10 @@
position: absolute;
}
</style>
</head>
<body>
<div id="canv" />
<script>
update();
var ws;
var tmout = null;
function update()
function update() // via HTTP (/json/live)
{
if (document.hidden) {
clearTimeout(tmout);
@ -57,8 +53,57 @@
clearTimeout(tmout);
tmout = setTimeout(update, 2500);
})
}
function S() { // Startup function (onload)
let wsOn = (window.location.href.indexOf("?ws") > 0);
if (!wsOn) {update(); return;}
// Initialize WebSocket connection
try {
ws = top.window.ws;
} catch (e) {}
if (ws && ws.readyState === WebSocket.OPEN) {
//console.info("Peek uses top WS");
ws.send("{'lv':true}");
} else {
//console.info("Peek WS opening");
let l = window.location;
let pathn = l.pathname;
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
let url = l.origin.replace("http","ws");
if (paths.length > 1) {
url += "/" + paths[0];
}
ws = new WebSocket(url+"/ws");
ws.onopen = function () {
//console.info("Peek WS open");
ws.send("{'lv':true}");
}
}
ws.binaryType = "arraybuffer";
ws.addEventListener('message', (e) => {
try {
if (toString.call(e.data) === '[object ArrayBuffer]') {
let leds = new Uint8Array(event.data);
if (leds[0] != 76) return; //'L'
let str = "linear-gradient(90deg,";
let len = leds.length;
let start = leds[1]==2 ? 4 : 2; // 1 = 1D, 2 = 1D/2D (leds[2]=w, leds[3]=h)
for (i = start; i < len; i+=3) {
str += `rgb(${leds[i]},${leds[i+1]},${leds[i+2]})`;
if (i < len -3) str += ","
}
str += ")";
document.getElementById("canv").style.background = str;
}
} catch (err) {
console.error("Peek WS error:",err);
}
});
}
</script>
</head>
<body onload="S()">
<div id="canv"></div>
</body>
</html>

View File

@ -1,68 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<meta charset="utf-8">
<meta name="theme-color" content="#222222">
<title>WLED Live Preview</title>
<style>
body {
margin: 0;
}
#canv {
background: black;
filter: brightness(175%);
width: 100%;
height: 100%;
position: absolute;
}
</style>
</head>
<body>
<div id="canv"></div>
<script>
var ws;
try {
ws = top.window.ws;
} catch (e) {}
if (ws && ws.readyState === WebSocket.OPEN) {
//console.info("Peek uses top WS");
ws.send("{'lv':true}");
} else {
//console.info("Peek WS opening");
let l = window.location;
let pathn = l.pathname;
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
let url = l.origin.replace("http","ws");
if (paths.length > 1) {
url += "/" + paths[0];
}
ws = new WebSocket(url+"/ws");
ws.onopen = function () {
//console.info("Peek WS open");
ws.send("{'lv':true}");
}
}
ws.binaryType = "arraybuffer";
ws.addEventListener('message', (e) => {
try {
if (toString.call(e.data) === '[object ArrayBuffer]') {
let leds = new Uint8Array(event.data);
if (leds[0] != 76) return; //'L'
let str = "linear-gradient(90deg,";
let len = leds.length;
let start = leds[1]==2 ? 4 : 2; // 1 = 1D, 2 = 1D/2D (leds[2]=w, leds[3]=h)
for (i = start; i < len; i+=3) {
str += `rgb(${leds[i]},${leds[i+1]},${leds[i+2]})`;
if (i < len -3) str += ","
}
str += ")";
document.getElementById("canv").style.background = str;
}
} catch (err) {
console.error("Peek WS error:",err);
}
});
</script>
</body>
</html>

View File

@ -27,7 +27,8 @@
"segexp" : "Always expand first segment",
"css": "Enable custom CSS",
"hdays": "Enable custom Holidays list",
"hdays": "Enable Pixel Magic Tool",
"fxdef": "Use effect default parameters",
"pxm": "Enable Pixel Magic Tool"
},
"theme":{
"alpha": {

View File

@ -11,6 +11,7 @@
d.um_p = [];
d.rsvd = [];
d.ro_gpio = [];
d.extra = [];
var umCfg = {};
var pins = [], pinO = [], owner;
var loc = false, locip, locproto = "http:";
@ -30,16 +31,11 @@
// success event
scE.addEventListener("load", () => {
GetV();
for (let k=0; k<d.rsvd.length; k++) { pins.push(d.rsvd[k]); pinO.push("rsvd"); }
if (d.um_p[0]==-1) d.um_p.shift();
d.Sf.SDA.max = d.max_gpio;
d.Sf.SCL.max = d.max_gpio;
d.Sf.MOSI.max = d.max_gpio;
d.Sf.SCLK.max = d.max_gpio;
d.Sf.MISO.max = d.max_gpio;
let inp = d.getElementsByTagName("input");
for (let i of inp) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
pinDropdowns();
for (let r of d.rsvd) { pins.push(r); pinO.push("rsvd"); } // reserved pins
if (d.um_p[0]==-1) d.um_p.shift(); // remove filler
d.Sf.SDA.max = d.Sf.SCL.max = d.Sf.MOSI.max = d.Sf.SCLK.max = d.Sf.MISO.max = d.max_gpio;
//for (let i of d.getElementsByTagName("input")) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
pinDropdowns(); // convert INPUT to SELECT for pins
});
// error event
scE.addEventListener("error", (ev) => {
@ -77,6 +73,7 @@
function isF(n) { return n === +n && n !== (n|0); }
function isI(n) { return n === +n && n === (n|0); }
function check(o,k) { // input object, pin owner key
/* no longer necessary with pin dropdown fields
var n = o.name.replace("[]","").substr(-3);
if (o.type=="number" && n.substr(0,3)=="pin") {
for (var i=0; i<pins.length; i++) {
@ -99,6 +96,7 @@
if (o.value==pins[i] || o.value<-1 || o.value>d.max_gpio) { o.style.color="red"; break; } else o.style.color=d.ro_gpio.some((e)=>e==parseInt(o.value,10))?"orange":"#fff";
}
}
*/
}
function getPins(o) {
if (isO(o)) {
@ -181,6 +179,13 @@
if (j === v) opt.selected = true; // this is "our" pin
else if (pins.includes(j)) opt.disabled = true; // someone else's pin
}
let um = i.name.split(":")[0];
d.extra.forEach((o)=>{
if (o[um] && o[um].pin) o[um].pin.forEach((e)=>{
let opt = addOption(sel,e[0],e[1]);
if (e[1]==v) opt.selected = true;
});
});
}
}
}
@ -198,15 +203,17 @@
i.text = "unused";
return
}
i.text = i.value;
if (i.value==oldV) {
i.disabled = false;
if (i.value<100) { // TODO remove this hack and use d.extra
i.text = i.value;
if (i.value==oldV) {
i.disabled = false;
}
if (i.value==e.value) {
i.disabled = true;
i.text += ` ${txt}`;
}
if (d.ro_gpio.includes(parseInt(i.value))) i.text += " (R/O)";
}
if (i.value==e.value) {
i.disabled = true;
i.text += ` ${txt}`;
}
if (d.ro_gpio.includes(parseInt(i.value))) i.text += " (R/O)";
});
}
}
@ -235,7 +242,7 @@
var att = inp.attributes[i];
// type and value don't apply, so skip them
// ** you might also want to skip style, or others -- modify as needed **
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style') {
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style' && att.name != 'oninput' && att.name != 'max' && att.name != 'min') {
sel.setAttribute(att.name, att.value);
}
}
@ -243,7 +250,6 @@
sel.setAttribute("onchange", "UI(this)");
// finally, replace the old input element with the new select element
inp.parentElement.replaceChild(sel, inp);
if (arr[0].type==="hidden") arr[0].parentElement.removeChild(arr[0]); // remove hidden element from DOM
return sel;
}
return null;

View File

@ -193,6 +193,17 @@
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
<i>Can help with connectivity issues.<br>
Do not enable if WiFi is working correctly, increases power consumption.</i>
<div id="remd">
<h3>Wireless Remote</h3>
<i>Listen for events over ESP-NOW<br>
Keep disabled if not using a remote, increases power consumption.<br></i>
Enable Remote: <input type="checkbox" name="RE"><br>
Hardware MAC: <input type="text" name="RMAC"><br>
Last Seen: <span class="rlid">None</span> <br>
</div>
<div id="ethd">
<h3>Ethernet Type</h3>
<select name="ETH">

View File

@ -171,6 +171,7 @@ async function onLoad()
// detect reverse proxy and/or HTTPS
let pathn = l.pathname;
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
if (paths[0]==="sliders") paths.shift();
//while (paths[0]==="") paths.shift();
locproto = l.protocol;
locip = l.hostname + (l.port ? ":" + l.port : "");

View File

@ -57,7 +57,7 @@
Connect the module to your local WiFi here!<br>
<button onclick="window.location.href='./settings/wifi'">WiFi settings</button><br>
<i>Just trying this out in AP mode?</i><br>
<button onclick="window.location.href='./sliders'">To the controls!</button><br>
<button onclick="window.location.href='./?sliders'">To the controls!</button><br>
</div>
</body>
</html>

View File

@ -104,10 +104,20 @@ void sendHuePoll();
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
//improv.cpp
enum ImprovRPCType {
Command_Wifi = 0x01,
Request_State = 0x02,
Request_Info = 0x03,
Request_Scan = 0x04
};
void handleImprovPacket();
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings = 0, const char **strings = nullptr);
void sendImprovStateResponse(uint8_t state, bool error = false);
void sendImprovInfoResponse();
void sendImprovRPCResponse(byte commandId);
void startImprovWifiScan();
void handleImprovWifiScan();
void sendImprovIPRPCResult(ImprovRPCType type);
//ir.cpp
void applyRepeatActions();
@ -200,12 +210,16 @@ void serializePlaylist(JsonObject obj);
void initPresetsFile();
void handlePresets();
bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE);
void applyPresetWithFallback(uint8_t presetID, uint8_t callMode, uint8_t effectID = 0, uint8_t paletteID = 0);
inline bool applyTemporaryPreset() {return applyPreset(255);};
void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject());
inline void saveTemporaryPreset() {savePreset(255);};
void deletePreset(byte index);
bool getPresetName(byte index, String& name);
//remote.cpp
void handleRemote();
//set.cpp
bool isAsterisksOnly(const char* str, byte maxLen);
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage);
@ -335,6 +349,7 @@ void releaseJSONBufferLock();
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr);
int16_t extractModeDefaults(uint8_t mode, const char *segVar);
void checkSettingsPIN(const char *pin);
uint16_t crc16(const unsigned char* data_p, size_t length);
um_data_t* simulateSound(uint8_t simulationId);
void enumerateLedmaps();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,11 @@
#define DIMPROV_PRINTF(x...)
#endif
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
#undef WLED_DISABLE_IMPROV_WIFISCAN
#define WLED_DISABLE_IMPROV_WIFISCAN
#endif
#define IMPROV_VERSION 1
void parseWiFiCommand(char *rpcData);
@ -28,20 +33,14 @@ enum ImprovPacketByte {
RPC_CommandType = 9
};
enum ImprovRPCType {
Command_Wifi = 0x01,
Request_State = 0x02,
Request_Info = 0x03
};
//File dbgf;
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
static bool improvWifiScanRunning = false;
#endif
//blocking function to parse an Improv Serial packet
void handleImprovPacket() {
uint8_t header[6] = {'I','M','P','R','O','V'};
//dbgf = WLED_FS.open("/improv.log","a");
bool timeout = false;
uint8_t waitTime = 25;
uint16_t packetByte = 0;
@ -62,12 +61,11 @@ void handleImprovPacket() {
byte next = Serial.read();
DIMPROV_PRINT("Received improv byte: "); DIMPROV_PRINTF("%x\r\n",next);
//f.write(next);
switch (packetByte) {
case ImprovPacketByte::Version: {
if (next != IMPROV_VERSION) {
DIMPROV_PRINTLN(F("Invalid version"));
//dbgf.close();
return;
}
break;
@ -75,7 +73,6 @@ void handleImprovPacket() {
case ImprovPacketByte::PacketType: {
if (next != ImprovPacketType::RPC_Command) {
DIMPROV_PRINTF("Non RPC-command improv packet type %i\n",next);
//dbgf.close();
return;
}
if (!improvActive) improvActive = 1;
@ -89,7 +86,6 @@ void handleImprovPacket() {
if (checksum != next) {
DIMPROV_PRINTF("Got RPC checksum %i, expected %i",next,checksum);
sendImprovStateResponse(0x01, true);
//dbgf.close();
return;
}
@ -100,22 +96,23 @@ void handleImprovPacket() {
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
if (Network.isConnected()) improvState = 0x04; //provisioned
sendImprovStateResponse(improvState, false);
if (improvState == 0x04) sendImprovRPCResponse(ImprovRPCType::Request_State);
if (improvState == 0x04) sendImprovIPRPCResult(ImprovRPCType::Request_State);
break;
}
case ImprovRPCType::Request_Info: sendImprovInfoResponse(); break;
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
case ImprovRPCType::Request_Scan: startImprovWifiScan(); break;
#endif
default: {
DIMPROV_PRINTF("Unknown RPC command %i\n",next);
sendImprovStateResponse(0x02, true);
}
}
//dbgf.close();
return;
}
if (packetByte < 6) { //check header
if (next != header[packetByte]) {
DIMPROV_PRINTLN(F("Invalid improv header"));
//dbgf.close();
return;
}
} else if (packetByte > 9) { //RPC data
@ -128,7 +125,6 @@ void handleImprovPacket() {
checksum += next;
packetByte++;
}
//dbgf.close();
}
void sendImprovStateResponse(uint8_t state, bool error) {
@ -147,79 +143,116 @@ void sendImprovStateResponse(uint8_t state, bool error) {
Serial.write('\n');
}
void sendImprovRPCResponse(byte commandId) {
// used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan()
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) {
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
uint8_t packetLen = 12;
char out[64] = {'I','M','P','R','O','V'};
char out[256] = {'I','M','P','R','O','V'};
out[6] = IMPROV_VERSION;
out[7] = ImprovPacketType::RPC_Response;
out[8] = 2; //Length (set below)
out[9] = commandId;
out[10] = 0; //Data len (set below)
out[11] = '\0'; //URL len (set below)
//out[8] = 2; //Length (set below)
out[9] = type;
//out[10] = 0; //Data len (set below)
uint16_t pos = 11;
if (Network.isConnected())
{
IPAddress localIP = Network.localIP();
uint8_t len = sprintf(out+12, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
if (len > 24) return; //sprintf fail?
out[11] = len;
out[10] = 1 + len;
out[8] = 3 + len; //RPC command type + data len + url len + url
packetLen = 13 + len;
for (uint8_t s = 0; s < n_strings; s++) {
size_t len = strlen(strings[s]);
if (pos + len > 254) continue; // simple buffer overflow guard
out[pos++] = len;
strcpy(out + pos, strings[s]);
pos += len;
}
packetLen = pos +1;
out[8] = pos -9; // Length of packet (excluding first 9 header bytes and final checksum byte)
out[10] = pos -11; // Data len
uint8_t checksum = 0;
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
out[packetLen -1] = checksum;
Serial.write((uint8_t*)out, packetLen);
Serial.write('\n');
DIMPROV_PRINT("RPC result checksum");
DIMPROV_PRINTLN(checksum);
}
void sendImprovIPRPCResult(ImprovRPCType type) {
if (Network.isConnected())
{
char urlStr[64];
IPAddress localIP = Network.localIP();
uint8_t len = sprintf(urlStr, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
if (len > 24) return; //sprintf fail?
const char *str[1] = {urlStr};
sendImprovRPCResult(type, 1, str);
} else {
sendImprovRPCResult(type, 0);
}
improvActive = 1; //no longer provisioning
}
void sendImprovInfoResponse() {
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
uint8_t packetLen = 12;
char out[128] = {'I','M','P','R','O','V'};
out[6] = IMPROV_VERSION;
out[7] = ImprovPacketType::RPC_Response;
//out[8] = 2; //Length (set below)
out[9] = ImprovRPCType::Request_Info;
//out[10] = 0; //Data len (set below)
out[11] = 4; //Firmware len ("WLED")
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
uint8_t lengthSum = 17;
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.14.0-b3/%i"),VERSION);
out[16] = vlen; lengthSum += vlen;
uint8_t hlen = 7;
#ifdef ESP8266
strcpy(out+lengthSum+1,"esp8266");
#else
hlen = 5;
strcpy(out+lengthSum+1,"esp32");
#endif
out[lengthSum] = hlen;
lengthSum += hlen + 1;
const char* bString =
#ifdef ESP8266
"esp8266"
#elif CONFIG_IDF_TARGET_ESP32C3
"esp32-c3"
#elif CONFIG_IDF_TARGET_ESP32S2
"esp32-s2"
#elif CONFIG_IDF_TARGET_ESP32S3
"esp32-s3";
#else // ESP32
"esp32";
#endif
;
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
strcpy(out+lengthSum+1,useMdnsName ? cmDNS : serverDescription);
uint8_t nlen = strlen(useMdnsName ? cmDNS : serverDescription);
out[lengthSum] = nlen;
lengthSum += nlen + 1;
char vString[20];
sprintf_P(vString, PSTR("0.14.0-b3/%i"), VERSION);
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
packetLen = lengthSum +1;
out[8] = lengthSum -9;
out[10] = lengthSum -11;
uint8_t checksum = 0;
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
out[packetLen -1] = checksum;
Serial.write((uint8_t*)out, packetLen);
Serial.write('\n');
DIMPROV_PRINT("Info checksum");
DIMPROV_PRINTLN(checksum);
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
}
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
void startImprovWifiScan() {
if (improvWifiScanRunning) return;
WiFi.scanNetworks(true);
improvWifiScanRunning = true;
}
void handleImprovWifiScan() {
if (!improvWifiScanRunning) return;
int16_t status = WiFi.scanComplete();
if (status == WIFI_SCAN_RUNNING) return;
// here scan completed or failed (-2)
improvWifiScanRunning = false;
for (int i = 0; i < status; i++) {
char rssiStr[8];
sprintf(rssiStr, "%d", WiFi.RSSI(i));
#ifdef ESP8266
bool isOpen = WiFi.encryptionType(i) == ENC_TYPE_NONE;
#else
bool isOpen = WiFi.encryptionType(i) == WIFI_AUTH_OPEN;
#endif
char ssidStr[33];
strcpy(ssidStr, WiFi.SSID(i).c_str());
const char *str[3] = {ssidStr, rssiStr, isOpen ? "NO":"YES"};
sendImprovRPCResult(ImprovRPCType::Request_Scan, 3, str);
}
sendImprovRPCResult(ImprovRPCType::Request_Scan, 0);
WiFi.scanDelete();
}
#else
void startImprovWifiScan() {}
void handleImprovWifiScan() {}
#endif
void parseWiFiCommand(char* rpcData) {
uint8_t len = rpcData[0];
if (!len || len > 126) return;

View File

@ -70,13 +70,9 @@ void decBrightness()
}
}
// apply preset or fallback to a effect and palette if it doesn't exist
void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
{
applyPreset(presetID, CALL_MODE_BUTTON_PRESET);
//these two will be overwritten if preset exists in handlePresets()
effectCurrent = effectID;
effectPalette = paletteID;
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
}
byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte higherBoundary)

View File

@ -34,7 +34,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
uint16_t start = elem["start"] | seg.start;
if (stop < 0) {
uint16_t len = elem["len"];
int len = elem["len"];
stop = (len > 0) ? start + len : seg.stop;
}
// 2D segments
@ -70,9 +70,10 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
const char * name = elem["n"].as<const char*>();
size_t len = 0;
if (name != nullptr) len = strlen(name);
if (len > 0 && len < 33) {
if (len > 0) {
if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN;
seg.name = new char[len+1];
if (seg.name) strlcpy(seg.name, name, 33);
if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1);
} else {
// but is empty (already deleted above)
elem.remove("n");
@ -425,7 +426,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
if (!root["pd"].isNull() && stateChanged) {
currentPreset = root[F("pd")] | currentPreset;
if (root["win"].isNull()) presetCycCurr = currentPreset;
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise it was set in handleSet() [set.cpp]
presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after
//unloadPlaylist(); // applying a preset unloads the playlist, may be needed here too?
} else if (!root["ps"].isNull()) {
@ -472,7 +473,7 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
root[F("stopY")] = seg.stopY;
}
}
if (!forPreset) root["len"] = seg.stop - seg.start;
if (!forPreset) root["len"] = (seg.stop >= seg.start) ? (seg.stop - seg.start) : 0;
root["grp"] = seg.grouping;
root[F("spc")] = seg.spacing;
root[F("of")] = seg.offset;

View File

@ -104,6 +104,7 @@ void stateUpdated(byte callMode) {
if (stateChanged) currentPreset = 0; //something changed, so we are no longer in the preset
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
if (bri != briOld && nodeBroadcastEnabled) sendSysInfoUDP(); // update on state
//set flag to update ws and mqtt
interfaceUpdateCallMode = callMode;
@ -146,8 +147,8 @@ void stateUpdated(byte callMode) {
if (transitionActive) {
briOld = briT;
tperLast = 0;
}
strip.setTransitionMode(true); // force all segments to transition mode
} else
strip.setTransitionMode(true); // force all segments to transition mode
transitionActive = true;
transitionStartTime = millis();
} else {

View File

@ -120,6 +120,15 @@ bool applyPreset(byte index, byte callMode)
return true;
}
// apply preset or fallback to a effect and palette if it doesn't exist
void applyPresetWithFallback(uint8_t index, uint8_t callMode, uint8_t effectID, uint8_t paletteID)
{
applyPreset(index, callMode);
//these two will be overwritten if preset exists in handlePresets()
effectCurrent = effectID;
effectPalette = paletteID;
}
void handlePresets()
{
if (presetToSave) {
@ -171,7 +180,7 @@ void handlePresets()
fdo.remove("ps"); // remove load request for presets to prevent recursive crash (if not called by button and contains preset cycling string "1~5~")
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
}
if (!errorFlag && tmpPreset < 255 && changePreset) presetCycCurr = currentPreset = tmpPreset;
if (!errorFlag && tmpPreset < 255 && changePreset) currentPreset = tmpPreset;
#if defined(ARDUINO_ARCH_ESP32)
//Aircoookie recommended not to delete buffer

200
wled00/remote.cpp Normal file
View File

@ -0,0 +1,200 @@
#include "wled.h"
#define ESP_NOW_STATE_UNINIT 0
#define ESP_NOW_STATE_ON 1
#define ESP_NOW_STATE_ERROR 2
#define NIGHT_MODE_DEACTIVATED -1
#define NIGHT_MODE_BRIGHTNESS 5
#define WIZMOTE_BUTTON_ON 1
#define WIZMOTE_BUTTON_OFF 2
#define WIZMOTE_BUTTON_NIGHT 3
#define WIZMOTE_BUTTON_ONE 16
#define WIZMOTE_BUTTON_TWO 17
#define WIZMOTE_BUTTON_THREE 18
#define WIZMOTE_BUTTON_FOUR 19
#define WIZMOTE_BUTTON_BRIGHT_UP 9
#define WIZMOTE_BUTTON_BRIGHT_DOWN 8
#ifdef WLED_DISABLE_ESPNOW
void handleRemote(){}
#else
// This is kind of an esoteric strucure because it's pulled from the "Wizmote"
// product spec. That remote is used as the baseline for behavior and availability
// since it's broadly commercially available and works out of the box as a drop-in
typedef struct message_structure {
uint8_t program; // 0x91 for ON button, 0x81 for all others
uint8_t seq[4]; // Incremetal sequence number 32 bit unsigned integer LSB first
uint8_t byte5 = 32; // Unknown
uint8_t button; // Identifies which button is being pressed
uint8_t byte8 = 1; // Unknown, but always 0x01
uint8_t byte9 = 100; // Unnkown, but always 0x64
uint8_t byte10; // Unknown, maybe checksum
uint8_t byte11; // Unknown, maybe checksum
uint8_t byte12; // Unknown, maybe checksum
uint8_t byte13; // Unknown, maybe checksum
} message_structure;
static int esp_now_state = ESP_NOW_STATE_UNINIT;
static uint32_t last_seq = -1;
static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
static message_structure incoming;
// Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3
const byte brightnessSteps[] = {
6, 9, 14, 22, 33, 50, 75, 113, 170, 255
};
const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t);
bool nightModeActive() {
return brightnessBeforeNightMode != NIGHT_MODE_DEACTIVATED;
}
void activateNightMode() {
brightnessBeforeNightMode = bri;
bri = NIGHT_MODE_BRIGHTNESS;
}
bool resetNightMode() {
if (!nightModeActive()) {
return false;
}
bri = brightnessBeforeNightMode;
brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
return true;
}
// increment `bri` to the next `brightnessSteps` value
void brightnessUp() {
if (nightModeActive()) { return; }
// dumb incremental search is efficient enough for so few items
for (uint8_t index = 0; index < numBrightnessSteps; ++index) {
if (brightnessSteps[index] > bri) {
bri = brightnessSteps[index];
break;
}
}
}
// decrement `bri` to the next `brightnessSteps` value
void brightnessDown() {
if (nightModeActive()) { return; }
// dumb incremental search is efficient enough for so few items
for (int index = numBrightnessSteps - 1; index >= 0; --index) {
if (brightnessSteps[index] < bri) {
bri = brightnessSteps[index];
break;
}
}
}
void setOn() {
if (resetNightMode()) {
stateUpdated(CALL_MODE_BUTTON);
}
if (!bri) {
toggleOnOff();
}
}
void setOff() {
if (resetNightMode()) {
stateUpdated(CALL_MODE_BUTTON);
}
if (bri) {
toggleOnOff();
}
}
void presetWithFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID) {
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
}
// Callback function that will be executed when data is received
#ifdef ESP8266
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
#else
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
#endif
sprintf (last_signal_src, "%02x%02x%02x%02x%02x%02x",
mac [0], mac [1], mac [2], mac [3], mac [4], mac [5]);
if (strcmp(last_signal_src, linked_remote) != 0) {
DEBUG_PRINT(F("ESP Now Message Received from Unlinked Sender: "));
DEBUG_PRINTLN(last_signal_src);
return;
}
if (len != sizeof(incoming)) {
DEBUG_PRINT(F("Unknown incoming ESP Now message received of length "));
DEBUG_PRINTLN(len);
return;
}
memcpy(&(incoming.program), incomingData, sizeof(incoming));
uint32_t cur_seq = incoming.seq[0] | (incoming.seq[1] << 8) | (incoming.seq[2] << 16) | (incoming.seq[3] << 24);
if (cur_seq == last_seq) {
return;
}
DEBUG_PRINT(F("Incoming ESP Now Packet["));
DEBUG_PRINT(cur_seq);
DEBUG_PRINT(F("] from sender["));
DEBUG_PRINT(last_signal_src);
DEBUG_PRINT(F("] button: "));
DEBUG_PRINTLN(incoming.button);
switch (incoming.button) {
case WIZMOTE_BUTTON_ON : setOn(); stateUpdated(CALL_MODE_BUTTON); break;
case WIZMOTE_BUTTON_OFF : setOff(); stateUpdated(CALL_MODE_BUTTON); break;
case WIZMOTE_BUTTON_ONE : presetWithFallback(1, FX_MODE_STATIC, 0); resetNightMode(); break;
case WIZMOTE_BUTTON_TWO : presetWithFallback(2, FX_MODE_BREATH, 0); resetNightMode(); break;
case WIZMOTE_BUTTON_THREE : presetWithFallback(3, FX_MODE_FIRE_FLICKER, 0); resetNightMode(); break;
case WIZMOTE_BUTTON_FOUR : presetWithFallback(4, FX_MODE_RAINBOW, 0); resetNightMode(); break;
case WIZMOTE_BUTTON_NIGHT : activateNightMode(); stateUpdated(CALL_MODE_BUTTON); break;
case WIZMOTE_BUTTON_BRIGHT_UP : brightnessUp(); stateUpdated(CALL_MODE_BUTTON); break;
case WIZMOTE_BUTTON_BRIGHT_DOWN : brightnessDown(); stateUpdated(CALL_MODE_BUTTON); break;
default: break;
}
last_seq = cur_seq;
}
void handleRemote() {
if (enable_espnow_remote) {
if (esp_now_state == ESP_NOW_STATE_UNINIT) {
DEBUG_PRINTLN(F("Initializing ESP_NOW listener"));
// Init ESP-NOW
if (esp_now_init() != 0) {
DEBUG_PRINTLN(F("Error initializing ESP-NOW"));
esp_now_state = ESP_NOW_STATE_ERROR;
}
#ifdef ESP8266
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
#endif
esp_now_register_recv_cb(OnDataRecv);
esp_now_state = ESP_NOW_STATE_ON;
}
} else {
if (esp_now_state == ESP_NOW_STATE_ON) {
DEBUG_PRINTLN(F("Disabling ESP-NOW Remote Listener"));
if (esp_now_deinit() != 0) {
DEBUG_PRINTLN(F("Error de-initializing ESP-NOW"));
}
esp_now_state = ESP_NOW_STATE_UNINIT;
} else if (esp_now_state == ESP_NOW_STATE_ERROR) {
//Clear any error states (allows retrying by cycling)
esp_now_state = ESP_NOW_STATE_UNINIT;
}
}
}
#endif

View File

@ -7,19 +7,17 @@
//called upon POST settings form submit
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{
// PIN code request
if (subPage == 252)
if (subPage == SUBPAGE_PINREQ)
{
correctPIN = (strlen(settingsPIN)==0 || strncmp(settingsPIN, request->arg(F("PIN")).c_str(), 4)==0);
lastEditTime = millis();
checkSettingsPIN(request->arg(F("PIN")).c_str());
return;
}
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 7: DMX 8: usermods 9: N/A 10: 2D
if (subPage <1 || subPage >10 || !correctPIN) return;
if (subPage < 1 || subPage > 10 || !correctPIN) return;
//WIFI SETTINGS
if (subPage == 1)
if (subPage == SUBPAGE_WIFI)
{
strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33);
@ -36,6 +34,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
noWifiSleep = request->hasArg(F("WS"));
#ifndef WLED_DISABLE_ESPNOW
enable_espnow_remote = request->hasArg(F("RE"));
strlcpy(linked_remote,request->arg(F("RMAC")).c_str(), 13);
//Normalize MAC format to lowercase
strlcpy(linked_remote,strlwr(linked_remote), 13);
#endif
#ifdef WLED_USE_ETHERNET
ethernetType = request->arg(F("ETH")).toInt();
WLED::instance().initEthernet();
@ -58,7 +64,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
//LED SETTINGS
if (subPage == 2)
if (subPage == SUBPAGE_LEDS)
{
int t = 0;
@ -262,7 +268,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
//UI
if (subPage == 3)
if (subPage == SUBPAGE_UI)
{
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
syncToggleReceive = request->hasArg(F("ST"));
@ -280,7 +286,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
//SYNC
if (subPage == 4)
if (subPage == SUBPAGE_SYNC)
{
int t = request->arg(F("UP")).toInt();
if (t > 0) udpPort = t;
@ -379,7 +385,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
//TIME
if (subPage == 5)
if (subPage == SUBPAGE_TIME)
{
ntpEnabled = request->hasArg(F("NT"));
strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33);
@ -453,7 +459,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
//SECURITY
if (subPage == 6)
if (subPage == SUBPAGE_SEC)
{
if (request->hasArg(F("RS"))) //complete factory reset
{
@ -484,7 +490,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (otaLock && strcmp(otaPass,request->arg(F("OP")).c_str()) == 0)
{
// brute force protection: do not unlock even if correct if last save was less than 3 seconds ago
if (millis() - lastEditTime > 3000) pwdCorrect = true;
if (millis() - lastEditTime > PIN_RETRY_COOLDOWN) pwdCorrect = true;
}
if (!otaLock && request->arg(F("OP")).length() > 0)
{
@ -502,7 +508,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
if (subPage == 7)
if (subPage == SUBPAGE_DMX)
{
int t = request->arg(F("PU")).toInt();
if (t >= 0 && t <= 63999) e131ProxyUniverse = t;
@ -532,7 +538,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
#endif
//USERMODS
if (subPage == 8)
if (subPage == SUBPAGE_UM)
{
if (!requestJSONBufferLock(5)) return;
@ -672,7 +678,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
#ifndef WLED_DISABLE_2D
//2D panels
if (subPage == 10)
if (subPage == SUBPAGE_2D)
{
strip.isMatrix = request->arg(F("SOMP")).toInt();
strip.panel.clear(); // release memory if allocated
@ -709,10 +715,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
lastEditTime = millis();
// do not save if factory reset or LED settings (which are saved after LED re-init)
doSerializeConfig = subPage != 2 && !(subPage == 6 && doReboot);
if (subPage == 8) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after doSerializeConfig has been set)
doSerializeConfig = subPage != SUBPAGE_LEDS && !(subPage == SUBPAGE_SEC && doReboot);
if (subPage == SUBPAGE_UM) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after doSerializeConfig has been set)
#ifndef WLED_DISABLE_ALEXA
if (subPage == 4) alexaInit();
if (subPage == SUBPAGE_SYNC) alexaInit();
#endif
}

View File

@ -669,6 +669,7 @@ void sendSysInfoUDP()
#else
data[38] = NODE_TYPE_ID_UNDEFINED;
#endif
if (bri) data[38] |= 0x80U; // add on/off state
data[39] = ip[3]; // unit ID == last IP number
uint32_t build = VERSION;

View File

@ -373,6 +373,16 @@ int16_t extractModeDefaults(uint8_t mode, const char *segVar)
}
void checkSettingsPIN(const char* pin) {
if (!pin) return;
if (!correctPIN && millis() - lastEditTime < PIN_RETRY_COOLDOWN) return; // guard against PIN brute force
bool correctBefore = correctPIN;
correctPIN = (strlen(settingsPIN) == 0 || strncmp(settingsPIN, pin, 4) == 0);
if (correctBefore != correctPIN) createEditHandler(correctPIN);
lastEditTime = millis();
}
uint16_t crc16(const unsigned char* data_p, size_t length) {
uint8_t x;
uint16_t crc = 0xFFFF;
@ -493,8 +503,8 @@ um_data_t* simulateSound(uint8_t simulationId)
}
samplePeak = random8() > 250;
FFT_MajorPeak = volumeSmth;
maxVol = 10; // this gets feedback fro UI
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
maxVol = 31; // this gets feedback fro UI
binNum = 8; // this gets feedback fro UI
volumeRaw = volumeSmth;
my_magnitude = 10000.0 / 8.0f; //no idea if 10000 is a good value for FFT_Magnitude ???

View File

@ -46,7 +46,9 @@ void WLED::loop()
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
#endif
handleConnection();
handleRemote();
handleSerial();
handleImprovWifiScan();
handleNotifications();
handleTransitions();
#ifdef WLED_ENABLE_DMX
@ -138,7 +140,7 @@ void WLED::loop()
}
// 15min PIN time-out
if (strlen(settingsPIN)>0 && millis() - lastEditTime > 900000) {
if (strlen(settingsPIN)>0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) {
correctPIN = false;
createEditHandler(false);
}
@ -645,7 +647,6 @@ void WLED::initConnection()
ws.onEvent(wsEvent);
#endif
WiFi.disconnect(true); // close old connections
#ifdef ESP8266
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
@ -844,7 +845,7 @@ void WLED::handleConnection()
if (improvActive) {
if (improvError == 3) sendImprovStateResponse(0x00, true);
sendImprovStateResponse(0x04);
if (improvActive > 1) sendImprovRPCResponse(0x01);
if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi);
}
initInterfaces();
userConnected();

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2306130
#define VERSION 2307130
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG
@ -36,7 +36,7 @@
#undef WLED_ENABLE_ADALIGHT // disable has priority over enable
#endif
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
//#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
#ifndef WLED_DISABLE_LOXONE
#define WLED_ENABLE_LOXONE // uses 1.2kb
#endif
@ -44,6 +44,8 @@
#define WLED_ENABLE_WEBSOCKETS
#endif
//#define WLED_DISABLE_ESPNOW // Removes dependence on esp now
#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing FS content. Will also be disabled with OTA lock
// to toggle usb serial debug (un)comment the following line
@ -73,6 +75,9 @@
{
#include <user_interface.h>
}
#ifndef WLED_DISABLE_ESPNOW
#include <espnow.h>
#endif
#else // ESP32
#include <HardwareSerial.h> // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT)
#include <WiFi.h>
@ -89,6 +94,10 @@
#include <LittleFS.h>
#endif
#include "esp_task_wdt.h"
#ifndef WLED_DISABLE_ESPNOW
#include <esp_now.h>
#endif
#endif
#include <Wire.h>
#include <SPI.h>
@ -444,6 +453,12 @@ WLED_GLOBAL bool hueApplyColor _INIT(true);
WLED_GLOBAL uint16_t serialBaud _INIT(1152); // serial baud rate, multiply by 100
#ifndef WLED_DISABLE_ESPNOW
WLED_GLOBAL bool enable_espnow_remote _INIT(false);
WLED_GLOBAL char linked_remote[13] _INIT("");
WLED_GLOBAL char last_signal_src[13] _INIT("");
#endif
// Time CONFIG
WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros
WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format

File diff suppressed because one or more lines are too long

View File

@ -1,387 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\Dependencies">
<UniqueIdentifier>{72fe60da-ba26-45b4-82c1-bdff809975da}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Dependencies">
<UniqueIdentifier>{8880888d-efea-4189-a25a-834b7b3bb756}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="wled00.ino" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="__vm\.wled00.vsarduino.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_classic.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_mobile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_other.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_settings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FX.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\json\ArduinoJson-v6.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\json\AsyncJson-v6.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApi.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApiArduino.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkArduinoClient.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkConfig.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDateTime.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDebug.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDetectDevice.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkEveryN.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkFifo.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkHandlers.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkParam.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocol.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocolDefs.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\BlynkSimpleEsp.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTemplates.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTimer.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkUtility.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWidgetBase.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWiFiCommon.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Callbacks.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\DisconnectReasons.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\espalexa\Espalexa.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\espalexa\EspalexaDevice.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\e131\ESPAsyncE131.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Flags.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Helpers.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\MessageProperties.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="NpbWrapper.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\Packet.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\ParsingInformation.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Storage.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\time\Time.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\time\TimeLib.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\timezone\Timezone.h">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.hpp">
<Filter>Header Files\Dependencies</Filter>
</ClInclude>
<ClInclude Include="alexa.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="blynk.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="button.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="colors.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="const.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cronixie.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="dmx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="file.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_ui.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ir.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="json.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="led.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mqtt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="notify.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ntp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="overlay.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="set.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="usermod.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wled.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wled_eeprom.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wled_server.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="xml.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ir_codes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="palettes.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="FX.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FX_fcn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\utility.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkDebug.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkHandlers.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkTimer.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\time\DateStrings.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\espalexa\EspalexaDevice.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\e131\ESPAsyncE131.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\time\Time.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\timezone\Timezone.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.cpp">
<Filter>Source Files\Dependencies</Filter>
</ClCompile>
<ClCompile Include="alexa.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="blynk.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="button.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="colors.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cronixie.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="file.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ir.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="json.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="led.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mqtt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="notify.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ntp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="overlay.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="set.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="usermod.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wled.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wled_eeprom.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wled_server.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="xml.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@ -116,14 +116,6 @@ void initServer()
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*");
#ifdef WLED_ENABLE_WEBSOCKETS
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
if (handleIfNoneMatchCacheHeader(request)) return;
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveviewws, PAGE_liveviewws_length);
response->addHeader(FPSTR(s_content_enc),"gzip");
setStaticContentCacheHeaders(response);
request->send(response);
//request->send_P(200, "text/html", PAGE_liveviewws);
});
#ifndef WLED_DISABLE_2D
server.on("/liveview2D", HTTP_GET, [](AsyncWebServerRequest *request){
if (handleIfNoneMatchCacheHeader(request)) return;
@ -131,19 +123,16 @@ void initServer()
response->addHeader(FPSTR(s_content_enc),"gzip");
setStaticContentCacheHeaders(response);
request->send(response);
//request->send_P(200, "text/html", PAGE_liveviewws);
});
#endif
#else
#endif
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
if (handleIfNoneMatchCacheHeader(request)) return;
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveview, PAGE_liveview_length);
response->addHeader(FPSTR(s_content_enc),"gzip");
setStaticContentCacheHeaders(response);
request->send(response);
//request->send_P(200, "text/html", PAGE_liveview);
});
#endif
//settings page
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
@ -167,10 +156,6 @@ void initServer()
}
});
server.on("/sliders", HTTP_GET, [](AsyncWebServerRequest *request){
serveIndex(request);
});
server.on("/welcome", HTTP_GET, [](AsyncWebServerRequest *request){
serveSettings(request);
});
@ -201,6 +186,8 @@ void initServer()
request->send(400, "application/json", F("{\"error\":9}")); // ERR_JSON
return;
}
if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as<const char*>());
const String& url = request->url();
isConfig = url.indexOf("cfg") > -1;
if (!isConfig) {
@ -245,19 +232,15 @@ void initServer()
request->send(200, "text/plain", (String)ESP.getFreeHeap());
});
#ifdef WLED_ENABLE_USERMOD_PAGE
server.on("/u", HTTP_GET, [](AsyncWebServerRequest *request){
if (handleIfNoneMatchCacheHeader(request)) return;
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_usermod, PAGE_usermod_length);
response->addHeader(FPSTR(s_content_enc),"gzip");
setStaticContentCacheHeaders(response);
request->send(response);
//request->send_P(200, "text/html", PAGE_usermod);
});
//Deprecated, use of /json/state and presets recommended instead
server.on("/url", HTTP_GET, [](AsyncWebServerRequest *request){
URL_response(request);
});
#endif
server.on("/teapot", HTTP_GET, [](AsyncWebServerRequest *request){
serveMessage(request, 418, F("418. I'm a teapot."), F("(Tangible Embedded Advanced Project Of Twinkling)"), 254);
@ -354,9 +337,14 @@ void initServer()
serveMessage(request, 501, "Not implemented", F("DMX support is not enabled in this build."), 254);
});
#endif
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
if (captivePortal(request)) return;
serveIndexOrWelcome(request);
if (!showWelcomePage || request->hasArg(F("sliders"))){
serveIndex(request);
} else {
serveSettings(request);
}
});
#ifdef WLED_ENABLE_PIXART
@ -418,20 +406,9 @@ void initServer()
response->addHeader(FPSTR(s_content_enc),"gzip");
setStaticContentCacheHeaders(response);
request->send(response);
//request->send_P(404, "text/html", PAGE_404);
});
}
void serveIndexOrWelcome(AsyncWebServerRequest *request)
{
if (!showWelcomePage){
serveIndex(request);
} else {
serveSettings(request);
}
}
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
{
AsyncWebHeader* header = request->getHeader("If-None-Match");
@ -573,64 +550,62 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
if (url.indexOf("sett") >= 0)
{
if (url.indexOf(".js") > 0) subPage = 254;
else if (url.indexOf(".css") > 0) subPage = 253;
else if (url.indexOf("wifi") > 0) subPage = 1;
else if (url.indexOf("leds") > 0) subPage = 2;
else if (url.indexOf("ui") > 0) subPage = 3;
else if (url.indexOf("sync") > 0) subPage = 4;
else if (url.indexOf("time") > 0) subPage = 5;
else if (url.indexOf("sec") > 0) subPage = 6;
else if (url.indexOf("dmx") > 0) subPage = 7;
else if (url.indexOf("um") > 0) subPage = 8;
else if (url.indexOf("2D") > 0) subPage = 10;
else if (url.indexOf("lock") > 0) subPage = 251;
if (url.indexOf(".js") > 0) subPage = SUBPAGE_JS;
else if (url.indexOf(".css") > 0) subPage = SUBPAGE_CSS;
else if (url.indexOf("wifi") > 0) subPage = SUBPAGE_WIFI;
else if (url.indexOf("leds") > 0) subPage = SUBPAGE_LEDS;
else if (url.indexOf("ui") > 0) subPage = SUBPAGE_UI;
else if (url.indexOf("sync") > 0) subPage = SUBPAGE_SYNC;
else if (url.indexOf("time") > 0) subPage = SUBPAGE_TIME;
else if (url.indexOf("sec") > 0) subPage = SUBPAGE_SEC;
else if (url.indexOf("dmx") > 0) subPage = SUBPAGE_DMX;
else if (url.indexOf("um") > 0) subPage = SUBPAGE_UM;
else if (url.indexOf("2D") > 0) subPage = SUBPAGE_2D;
else if (url.indexOf("lock") > 0) subPage = SUBPAGE_LOCK;
}
else if (url.indexOf("/update") >= 0) subPage = 9; // update page, for PIN check
else if (url.indexOf("/update") >= 0) subPage = SUBPAGE_UPDATE; // update page, for PIN check
//else if (url.indexOf("/edit") >= 0) subPage = 10;
else subPage = 255; // welcome page
else subPage = SUBPAGE_WELCOME;
if (!correctPIN && strlen(settingsPIN) > 0 && (subPage > 0 && subPage < 11)) {
originalSubPage = subPage;
subPage = 252; // require PIN
subPage = SUBPAGE_PINREQ; // require PIN
}
// if OTA locked or too frequent PIN entry requests fail hard
if ((subPage == 1 && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < 3000))
if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < PIN_RETRY_COOLDOWN))
{
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_ota), 254); return;
}
if (post) { //settings/set POST request, saving
if (subPage != 1 || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
if (subPage != SUBPAGE_WIFI || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
char s[32];
char s2[45] = "";
switch (subPage) {
case 1: strcpy_P(s, PSTR("WiFi")); strcpy_P(s2, PSTR("Please connect to the new IP (if changed)")); forceReconnect = true; break;
case 2: strcpy_P(s, PSTR("LED")); break;
case 3: strcpy_P(s, PSTR("UI")); break;
case 4: strcpy_P(s, PSTR("Sync")); break;
case 5: strcpy_P(s, PSTR("Time")); break;
case 6: strcpy_P(s, PSTR("Security")); if (doReboot) strcpy_P(s2, PSTR("Rebooting, please wait ~10 seconds...")); break;
case 7: strcpy_P(s, PSTR("DMX")); break;
case 8: strcpy_P(s, PSTR("Usermods")); break;
case 10: strcpy_P(s, PSTR("2D")); break;
case 252: strcpy_P(s, correctPIN ? PSTR("PIN accepted") : PSTR("PIN rejected")); break;
case SUBPAGE_WIFI : strcpy_P(s, PSTR("WiFi")); strcpy_P(s2, PSTR("Please connect to the new IP (if changed)")); forceReconnect = true; break;
case SUBPAGE_LEDS : strcpy_P(s, PSTR("LED")); break;
case SUBPAGE_UI : strcpy_P(s, PSTR("UI")); break;
case SUBPAGE_SYNC : strcpy_P(s, PSTR("Sync")); break;
case SUBPAGE_TIME : strcpy_P(s, PSTR("Time")); break;
case SUBPAGE_SEC : strcpy_P(s, PSTR("Security")); if (doReboot) strcpy_P(s2, PSTR("Rebooting, please wait ~10 seconds...")); break;
case SUBPAGE_DMX : strcpy_P(s, PSTR("DMX")); break;
case SUBPAGE_UM : strcpy_P(s, PSTR("Usermods")); break;
case SUBPAGE_2D : strcpy_P(s, PSTR("2D")); break;
case SUBPAGE_PINREQ : strcpy_P(s, correctPIN ? PSTR("PIN accepted") : PSTR("PIN rejected")); break;
}
if (subPage == 252) {
createEditHandler(correctPIN);
} else
strcat_P(s, PSTR(" settings saved."));
if (subPage != SUBPAGE_PINREQ) strcat_P(s, PSTR(" settings saved."));
if (subPage == 252 && correctPIN) {
if (subPage == SUBPAGE_PINREQ && correctPIN) {
subPage = originalSubPage; // on correct PIN load settings page the user intended
} else {
if (!s2[0]) strcpy_P(s2, s_redirecting);
serveMessage(request, 200, s, s2, (subPage == 1 || ((subPage == 6 || subPage == 8) && doReboot)) ? 129 : (correctPIN ? 1 : 3));
bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot));
serveMessage(request, 200, s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3));
return;
}
}
@ -638,30 +613,30 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
AsyncWebServerResponse *response;
switch (subPage)
{
case 1: response = request->beginResponse_P(200, "text/html", PAGE_settings_wifi, PAGE_settings_wifi_length); break;
case 2: response = request->beginResponse_P(200, "text/html", PAGE_settings_leds, PAGE_settings_leds_length); break;
case 3: response = request->beginResponse_P(200, "text/html", PAGE_settings_ui, PAGE_settings_ui_length); break;
case 4: response = request->beginResponse_P(200, "text/html", PAGE_settings_sync, PAGE_settings_sync_length); break;
case 5: response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break;
case 6: response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
case SUBPAGE_WIFI : response = request->beginResponse_P(200, "text/html", PAGE_settings_wifi, PAGE_settings_wifi_length); break;
case SUBPAGE_LEDS : response = request->beginResponse_P(200, "text/html", PAGE_settings_leds, PAGE_settings_leds_length); break;
case SUBPAGE_UI : response = request->beginResponse_P(200, "text/html", PAGE_settings_ui, PAGE_settings_ui_length); break;
case SUBPAGE_SYNC : response = request->beginResponse_P(200, "text/html", PAGE_settings_sync, PAGE_settings_sync_length); break;
case SUBPAGE_TIME : response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break;
case SUBPAGE_SEC : response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
#ifdef WLED_ENABLE_DMX
case 7: response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
case SUBPAGE_DMX : response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
#endif
case 8: response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
case 9: response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
case SUBPAGE_UM : response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
case SUBPAGE_UPDATE : response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
#ifndef WLED_DISABLE_2D
case 10: response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
case SUBPAGE_2D : response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
#endif
case 251: {
case SUBPAGE_LOCK : {
correctPIN = !strlen(settingsPIN); // lock if a pin is set
createEditHandler(correctPIN);
serveMessage(request, 200, strlen(settingsPIN) > 0 ? PSTR("Settings locked") : PSTR("No PIN set"), FPSTR(s_redirecting), 1);
return;
}
case 252: response = request->beginResponse_P(200, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
case 253: response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length); break;
case 254: serveSettingsJS(request); return;
case 255: response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
case SUBPAGE_PINREQ : response = request->beginResponse_P(200, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
case SUBPAGE_CSS : response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length); break;
case SUBPAGE_JS : serveSettingsJS(request); return;
case SUBPAGE_WELCOME : response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
default: response = request->beginResponse_P(200, "text/html", PAGE_settings, PAGE_settings_length); break;
}
response->addHeader(FPSTR(s_content_enc),"gzip");

View File

@ -54,14 +54,15 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
}
releaseJSONBufferLock(); // will clean fileDoc
// force broadcast in 500ms after updating client
if (verboseResponse) {
sendDataWs(client);
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
} else {
// we have to send something back otherwise WS connection closes
client->text(F("{\"success\":true}"));
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
if (verboseResponse) {
sendDataWs(client);
} else {
// we have to send something back otherwise WS connection closes
client->text(F("{\"success\":true}"));
}
// force broadcast in 500ms after updating client
//lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500); // ESP8266 does not like this
}
}
} else {

View File

@ -72,55 +72,6 @@ void XML_response(AsyncWebServerRequest *request, char* dest)
if (request != nullptr) request->send(200, "text/xml", obuf);
}
//Deprecated, use of /json/state and presets recommended instead
void URL_response(AsyncWebServerRequest *request)
{
char sbuf[256];
char s2buf[100];
obuf = s2buf;
olen = 0;
char s[16];
oappend(SET_F("http://"));
IPAddress localIP = Network.localIP();
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
oappend(s);
oappend(SET_F("/win&A="));
oappendi(bri);
oappend(SET_F("&CL=h"));
for (int i = 0; i < 3; i++)
{
sprintf(s,"%02X", col[i]);
oappend(s);
}
oappend(SET_F("&C2=h"));
for (int i = 0; i < 3; i++)
{
sprintf(s,"%02X", colSec[i]);
oappend(s);
}
oappend(SET_F("&FX="));
oappendi(effectCurrent);
oappend(SET_F("&SX="));
oappendi(effectSpeed);
oappend(SET_F("&IX="));
oappendi(effectIntensity);
oappend(SET_F("&FP="));
oappendi(effectPalette);
obuf = sbuf;
olen = 0;
oappend(SET_F("<html><body><a href=\""));
oappend(s2buf);
oappend(SET_F("\" target=\"_blank\">"));
oappend(s2buf);
oappend(SET_F("</a></body></html>"));
if (request != nullptr) request->send(200, "text/html", obuf);
}
void extractPin(JsonObject &obj, const char *key) {
if (obj[key].is<JsonArray>()) {
JsonArray pins = obj[key].as<JsonArray>();
@ -285,7 +236,7 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage <0 || subPage >10) return;
if (subPage == 0)
if (subPage == SUBPAGE_MENU)
{
#ifndef WLED_DISABLE_2D // include only if 2D is compiled in
oappend(PSTR("gId('2dbtn').style.display='';"));
@ -295,7 +246,7 @@ void getSettingsJS(byte subPage, char* dest)
#endif
}
if (subPage == 1)
if (subPage == SUBPAGE_WIFI)
{
sappends('s',SET_F("CS"),clientSSID);
@ -328,6 +279,14 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("AC"),apChannel);
sappend('c',SET_F("WS"),noWifiSleep);
#ifndef WLED_DISABLE_ESPNOW
sappend('c',SET_F("RE"),enable_espnow_remote);
sappends('s',SET_F("RMAC"),linked_remote);
#else
//hide remote settings if not compiled
oappend(SET_F("document.getElementById('remd').style.display='none';"));
#endif
#ifdef WLED_USE_ETHERNET
sappend('v',SET_F("ETH"),ethernetType);
#else
@ -360,9 +319,22 @@ void getSettingsJS(byte subPage, char* dest)
{
sappends('m',SET_F("(\"sip\")[1]"),(char*)F("Not active"));
}
#ifndef WLED_DISABLE_ESPNOW
if (last_signal_src[0] != 0) //Have seen an ESP-NOW Remote
{
sappends('m',SET_F("(\"rlid\")[0]"),last_signal_src);
} else if (!enable_espnow_remote)
{
sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("(Enable remote to listen)"));
} else
{
sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("None"));
}
#endif
}
if (subPage == 2)
if (subPage == SUBPAGE_LEDS)
{
char nS[32];
@ -493,7 +465,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("MSO"),!irApplyToAllSelected);
}
if (subPage == 3)
if (subPage == SUBPAGE_UI)
{
sappends('s',SET_F("DS"),serverDescription);
sappend('c',SET_F("ST"),syncToggleReceive);
@ -504,7 +476,7 @@ void getSettingsJS(byte subPage, char* dest)
#endif
}
if (subPage == 4)
if (subPage == SUBPAGE_SYNC)
{
sappend('v',SET_F("UP"),udpPort);
sappend('v',SET_F("U2"),udpPort2);
@ -597,7 +569,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("BD"),serialBaud);
}
if (subPage == 5)
if (subPage == SUBPAGE_TIME)
{
sappend('c',SET_F("NT"),ntpEnabled);
sappends('s',SET_F("NS"),ntpServerName);
@ -661,7 +633,7 @@ void getSettingsJS(byte subPage, char* dest)
}
}
if (subPage == 6)
if (subPage == SUBPAGE_SEC)
{
byte l = strlen(settingsPIN);
char fpass[l+1]; //fill PIN field with 0000
@ -683,7 +655,7 @@ void getSettingsJS(byte subPage, char* dest)
}
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
if (subPage == 7)
if (subPage == SUBPAGE_DMX)
{
sappend('v',SET_F("PU"),e131ProxyUniverse);
@ -710,7 +682,7 @@ void getSettingsJS(byte subPage, char* dest)
}
#endif
if (subPage == 8) //usermods
if (subPage == SUBPAGE_UM) //usermods
{
appendGPIOinfo();
oappend(SET_F("numM="));
@ -729,7 +701,7 @@ void getSettingsJS(byte subPage, char* dest)
usermods.appendConfigData();
}
if (subPage == 9) // update
if (subPage == SUBPAGE_UPDATE) // update
{
sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED "));
olen -= 2; //delete ";
@ -745,7 +717,7 @@ void getSettingsJS(byte subPage, char* dest)
oappend(SET_F(")\";"));
}
if (subPage == 10) // 2D matrices
if (subPage == SUBPAGE_2D) // 2D matrices
{
sappend('v',SET_F("SOMP"),strip.isMatrix);
#ifndef WLED_DISABLE_2D