Merge remote-tracking branch 'origin/ac_main' into mdev

This commit is contained in:
Ewoud
2022-12-19 14:00:52 +01:00
18 changed files with 2865 additions and 2268 deletions

View File

@@ -39,9 +39,9 @@
; MoonModules entries
; ===================
default_envs = esp32_4MB_min, esp32_4MB_max, esp32_16MB_max, esp8266_4MB_min, esp32_4MB_PSRAM_max, esp32S3_8MB_max, wemos_shield_esp32_4MB_max, wemos_shield_esp32_4MB_ICS4343x_max, wemos_shield_esp32_4MB_SPM1423_max, wemos_shield_esp32_4MB_LineIn_max, wemos_shield_esp32_16MB_max, , wemos_shield_esp32_16MB_ICS4343x_max, wemos_shield_esp32_16MB_SPM1423_max, wemos_shield_esp32_16MB_LineIn_max, esp32_pico_4MB_max
; default_envs = esp32_4MB_min, esp32_4MB_max, esp32_16MB_max, esp8266_4MB_min, esp32_4MB_PSRAM_max, esp32S3_8MB_max, wemos_shield_esp32_4MB_max, wemos_shield_esp32_4MB_ICS4343x_max, wemos_shield_esp32_4MB_SPM1423_max, wemos_shield_esp32_4MB_LineIn_max, wemos_shield_esp32_16MB_max, , wemos_shield_esp32_16MB_ICS4343x_max, wemos_shield_esp32_16MB_SPM1423_max, wemos_shield_esp32_16MB_LineIn_max, esp32_pico_4MB_max
; default_envs = esp32_4MB_min
; default_envs = esp32_4MB_max ; recommended default
default_envs = esp32_4MB_max ; recommended default
; default_envs = esp32_16MB_max
; default_envs = esp8266_4MB_min
; default_envs = esp32_4MB_V4_min

View File

@@ -169,13 +169,13 @@ float ARTI::arti_external_function(uint8_t function, float par1, float par2, flo
return floatNull;
}
case F_circle2D: {
uint16_t circleLength = min(strip.matrixWidth, strip.matrixHeight);
uint16_t circleLength = min(Segment::maxWidth, Segment::maxHeight);
uint16_t deltaWidth=0, deltaHeight=0;
if (circleLength < strip.matrixHeight) //portrait
deltaHeight = (strip.matrixHeight - circleLength) / 2;
if (circleLength < strip.matrixWidth) //portrait
deltaWidth = (strip.matrixWidth - circleLength) / 2;
if (circleLength < Segment::maxHeight) //portrait
deltaHeight = (Segment::maxHeight - circleLength) / 2;
if (circleLength < Segment::maxWidth) //portrait
deltaWidth = (Segment::maxWidth - circleLength) / 2;
float halfLength = (circleLength-1)/2.0;
@@ -524,8 +524,8 @@ bool ARTI::loop()
for (int i = 0; i< arti_get_external_variable(F_ledCount); i++)
{
if (function_symbol->function_scope->nrOfFormals == 2) {// 2D
ar->set(function_symbol->function_scope->symbols[0]->scope_index, i%strip.matrixWidth); // set x
ar->set(function_symbol->function_scope->symbols[1]->scope_index, i/strip.matrixWidth); // set y
ar->set(function_symbol->function_scope->symbols[0]->scope_index, i%Segment::maxWidth); // set x
ar->set(function_symbol->function_scope->symbols[1]->scope_index, i/Segment::maxWidth); // set y
}
else
ar->set(function_symbol->function_scope->symbols[0]->scope_index, i); // set x

56
usermods/sht/readme.md Normal file
View File

@@ -0,0 +1,56 @@
# SHT
Usermod to support various SHT i2c sensors like the SHT30, SHT31, SHT35 and SHT85
## Requirements
* "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85
## Usermod installation
Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the buildflag `-D USERMOD_SHT` and the below library dependencies.
ESP32:
```
[env:custom_esp32dev_usermod_sht]
extends = env:esp32dev
build_flags = ${common.build_flags_esp32}
-D USERMOD_SHT
lib_deps = ${esp32.lib_deps}
robtillaart/SHT85@~0.3.3
```
ESP8266:
```
[env:custom_d1_mini_usermod_sht]
extends = env:d1_mini
build_flags = ${common.build_flags_esp8266}
-D USERMOD_SHT
lib_deps = ${esp8266.lib_deps}
robtillaart/SHT85@~0.3.3
```
## MQTT Discovery for Home Assistant
If you're using Home Assistant and want to have the temperature and humidity available as entities in HA, you can tick the "Add-To-Home-Assistant-MQTT-Discovery" option in the usermod settings. If you have an MQTT broker configured under "Sync Settings" and it is connected, the mod will publish the auto discovery message to your broker and HA will instantly find it and create an entity each for the temperature and humidity.
### Publishing readings via MQTT
Regardless of having MQTT discovery ticked or not, the mod will always report temperature and humidity to the WLED MQTT topic of that instance, if you have a broker configured and it's connected.
## Configuration
Navigate to the "Config" and then to the "Usermods" section. If you compiled WLED with `-D USERMOD_SHT`, you will see the config for it there:
* SHT-Type:
* What it does: Select the SHT sensor type you want to use
* Possible values: SHT30, SHT31, SHT35, SHT85
* Default: SHT30
* Unit:
* What it does: Select which unit should be used to display the temperature in the info section. Also used when sending via MQTT discovery, see below.
* Possible values: Celsius, Fahrenheit
* Default: Celsius
* Add-To-HA-MQTT-Discovery:
* What it does: Makes the temperature and humidity available via MQTT discovery, so they're automatically added to Home Assistant, because that way it's typesafe.
* Possible values: Enabled/Disabled
* Default: Disabled
## Change log
2022-12
* First implementation.
## Credits
ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: https://discord.gg/WdbAauG

492
usermods/sht/usermod_sht.h Normal file
View File

@@ -0,0 +1,492 @@
#pragma once
#include "SHT85.h"
#define USERMOD_SHT_TYPE_SHT30 0
#define USERMOD_SHT_TYPE_SHT31 1
#define USERMOD_SHT_TYPE_SHT35 2
#define USERMOD_SHT_TYPE_SHT85 3
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
// SHT vars
SHT *shtTempHumidSensor; // Instance of SHT lib
byte shtType = 0; // SHT sensor type to be used. Default: SHT30
byte unitOfTemp = 0; // Temperature unit to be used. Default: Celsius (0 = Celsius, 1 = Fahrenheit)
bool shtInitDone = false; // Remembers if SHT sensor has been initialised
bool shtReadDataSuccess = false; // Did we have a successful data read and is a valid temperature and humidity available?
const byte shtI2cAddress = 0x44; // i2c address of the sensor. 0x44 is the default for all SHT sensors. Change this, if needed
unsigned long shtLastTimeUpdated = 0; // Remembers when we read data the last time
bool shtDataRequested = false; // Reading data is done async. This remembers if we asked the sensor to read data
float shtCurrentTempC = 0; // Last read temperature in Celsius
float shtCurrentTempF = 0; // Last read temperature in Fahrenheit
float shtCurrentHumidity = 0; // Last read humidity in RH%
void initShtTempHumiditySensor();
void cleanupShtTempHumiditySensor();
void cleanup();
bool isShtReady();
void publishTemperatureAndHumidityViaMqtt();
void publishHomeAssistantAutodiscovery();
void appendDeviceToMqttDiscoveryMessage(JsonDocument& root);
public:
// Strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _shtType[];
static const char _unitOfTemp[];
static const char _haMqttDiscovery[];
void setup();
void loop();
void onMqttConnect(bool sessionPresent);
void appendConfigData();
void addToConfig(JsonObject &root);
bool readFromConfig(JsonObject &root);
void addToJsonInfo(JsonObject& root);
float getTemperatureC();
float getTemperatureF();
float getHumidity();
uint16_t getId() { return USERMOD_ID_SHT; }
};
// Strings to reduce flash memory usage (used more than twice)
const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor";
const char ShtUsermod::_enabled[] PROGMEM = "Enabled";
const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type";
const char ShtUsermod::_unitOfTemp[] PROGMEM = "Unit";
const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-HA-MQTT-Discovery";
/**
* Initialise SHT sensor.
*
* Using the correct constructor according to config and initialises it using the
* global i2c pins.
*
* @return void
*/
void ShtUsermod::initShtTempHumiditySensor()
{
switch (shtType) {
case USERMOD_SHT_TYPE_SHT30: shtTempHumidSensor = (SHT *) new SHT30(); break;
case USERMOD_SHT_TYPE_SHT31: shtTempHumidSensor = (SHT *) new SHT31(); break;
case USERMOD_SHT_TYPE_SHT35: shtTempHumidSensor = (SHT *) new SHT35(); break;
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
}
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
cleanupShtTempHumiditySensor();
cleanup();
return;
}
shtInitDone = true;
}
/**
* Cleanup the SHT sensor.
*
* Properly calls "reset" for the sensor then releases it from memory.
*
* @return void
*/
void ShtUsermod::cleanupShtTempHumiditySensor()
{
if (isShtReady()) {
shtTempHumidSensor->reset();
}
delete shtTempHumidSensor;
shtInitDone = false;
}
/**
* Cleanup the mod completely.
*
* Calls ::cleanupShtTempHumiditySensor() to cleanup the SHT sensor and
* deallocates pins.
*
* @return void
*/
void ShtUsermod::cleanup()
{
if (isShtReady()) {
cleanupShtTempHumiditySensor();
}
if (pinAllocDone) {
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
pinManager.deallocateMultiplePins(pins, 2, PinOwner::HW_I2C);
pinAllocDone = false;
}
enabled = false;
}
/**
* Checks if the SHT sensor has been initialised.
*
* @return bool
*/
bool ShtUsermod::isShtReady()
{
return shtInitDone;
}
/**
* Publish temperature and humidity to WLED device topic.
*
* Will add a "/temperature" and "/humidity" topic to the WLED device topic.
* Temperature will be written in configured unit.
*
* @return void
*/
void ShtUsermod::publishTemperatureAndHumidityViaMqtt() {
if (!WLED_MQTT_CONNECTED) return;
char buf[128];
snprintf_P(buf, 127, PSTR("%s/temperature"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).c_str());
snprintf_P(buf, 127, PSTR("%s/humidity"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str());
}
/**
* If enabled, publishes HA MQTT device discovery topics.
*
* Will make Home Assistant add temperature and humidity as entities automatically.
*
* Note: Whenever usermods are part of the WLED integration in HA, this can be dropped.
*
* @return void
*/
void ShtUsermod::publishHomeAssistantAutodiscovery() {
if (!WLED_MQTT_CONNECTED) return;
char json_str[1024], buf[128];
size_t payload_size;
StaticJsonDocument<1024> json;
snprintf_P(buf, 127, PSTR("%s Temperature"), serverDescription);
json[F("name")] = buf;
snprintf_P(buf, 127, PSTR("%s/temperature"), mqttDeviceTopic);
json[F("stat_t")] = buf;
json[F("dev_cla")] = F("temperature");
json[F("stat_cla")] = F("measurement");
snprintf_P(buf, 127, PSTR("%s-temperature"), escapedMac.c_str());
json[F("uniq_id")] = buf;
json[F("unit_of_meas")] = F("°C");
appendDeviceToMqttDiscoveryMessage(json);
payload_size = serializeJson(json, json_str);
snprintf_P(buf, 127, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str());
mqtt->publish(buf, 0, true, json_str, payload_size);
json.clear();
snprintf_P(buf, 127, PSTR("%s Humidity"), serverDescription);
json[F("name")] = buf;
snprintf_P(buf, 127, PSTR("%s/humidity"), mqttDeviceTopic);
json[F("stat_t")] = buf;
json[F("dev_cla")] = F("humidity");
json[F("stat_cla")] = F("measurement");
snprintf_P(buf, 127, PSTR("%s-humidity"), escapedMac.c_str());
json[F("uniq_id")] = buf;
json[F("unit_of_meas")] = F("%");
appendDeviceToMqttDiscoveryMessage(json);
payload_size = serializeJson(json, json_str);
snprintf_P(buf, 127, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str());
mqtt->publish(buf, 0, true, json_str, payload_size);
haMqttDiscoveryDone = true;
}
/**
* Helper to add device information to MQTT discovery topic.
*
* @return void
*/
void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
JsonObject device = root.createNestedObject("dev");
device[F("ids")] = escapedMac.c_str();
device[F("name")] = serverDescription;
device[F("sw")] = versionString;
device[F("mdl")] = ESP.getChipModel();
device[F("mf")] = F("espressif");
}
/**
* Setup the mod.
*
* Allocates i2c pins as PinOwner::HW_I2C, so they can be allocated multiple times.
* And calls ::initShtTempHumiditySensor() to initialise the sensor.
*
* @see Usermod::setup()
* @see UsermodManager::setup()
*
* @return void
*/
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);
cleanup();
return;
}
pinAllocDone = true;
initShtTempHumiditySensor();
initDone = true;
}
firstRunDone = true;
}
/**
* Actually reading data (async) from the sensor every 30 seconds.
*
* If last reading is at least 30 seconds, it will trigger a reading using
* SHT::requestData(). We will then continiously check SHT::dataReady() if
* data is ready to be read. If so, it's read, stored locally and published
* via MQTT.
*
* @see Usermod::loop()
* @see UsermodManager::loop()
*
* @return void
*/
void ShtUsermod::loop()
{
if (!enabled || !initDone || strip.isUpdating()) return;
if (isShtReady()) {
if (millis() - shtLastTimeUpdated > 30000 && !shtDataRequested) {
shtTempHumidSensor->requestData();
shtDataRequested = true;
shtLastTimeUpdated = millis();
}
if (shtDataRequested) {
if (shtTempHumidSensor->dataReady()) {
if (shtTempHumidSensor->readData(false)) {
shtCurrentTempC = shtTempHumidSensor->getTemperature();
shtCurrentTempF = shtTempHumidSensor->getFahrenheit();
shtCurrentHumidity = shtTempHumidSensor->getHumidity();
publishTemperatureAndHumidityViaMqtt();
shtReadDataSuccess = true;
}
else {
shtReadDataSuccess = false;
}
shtDataRequested = false;
}
}
}
}
/**
* Whenever MQTT is connected, publish HA autodiscovery topics.
*
* Is only donce once.
*
* @see Usermod::onMqttConnect()
* @see UsermodManager::onMqttConnect()
*
* @return void
*/
void ShtUsermod::onMqttConnect(bool sessionPresent) {
if (haMqttDiscovery && !haMqttDiscoveryDone) publishHomeAssistantAutodiscovery();
}
/**
* Add dropdown for sensor type and unit to UM config page.
*
* @see Usermod::appendConfigData()
* @see UsermodManager::appendConfigData()
*
* @return void
*/
void ShtUsermod::appendConfigData() {
oappend(SET_F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(_shtType);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'SHT30',0);"));
oappend(SET_F("addOption(dd,'SHT31',1);"));
oappend(SET_F("addOption(dd,'SHT35',2);"));
oappend(SET_F("addOption(dd,'SHT85',3);"));
oappend(SET_F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(_unitOfTemp);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'Celsius',0);"));
oappend(SET_F("addOption(dd,'Fahrenheit',1);"));
}
/**
* Add config data to be stored in cfg.json.
*
* @see Usermod::addToConfig()
* @see UsermodManager::addToConfig()
*
* @return void
*/
void ShtUsermod::addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = enabled;
top[FPSTR(_shtType)] = shtType;
top[FPSTR(_unitOfTemp)] = unitOfTemp;
top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery;
}
/**
* Apply config on boot or save of UM config page.
*
* This is called whenever WLED boots and loads cfg.json, or when the UM config
* page is saved. Will properly re-instantiate the SHT class upon type change and
* publish HA discovery after enabling.
*
* @see Usermod::readFromConfig()
* @see UsermodManager::readFromConfig()
*
* @return bool
*/
bool ShtUsermod::readFromConfig(JsonObject &root)
{
JsonObject top = root[FPSTR(_name)];
if (top.isNull()) {
DEBUG_PRINTF("[%s] No config found. (Using defaults.)\n", _name);
return false;
}
bool oldEnabled = enabled;
byte oldShtType = shtType;
bool oldHaMqttDiscovery = haMqttDiscovery;
getJsonValue(top[FPSTR(_enabled)], enabled);
getJsonValue(top[FPSTR(_shtType)], shtType);
getJsonValue(top[FPSTR(_unitOfTemp)], unitOfTemp);
getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery);
// First run: reading from cfg.json, nothing to do here, will be all done in setup()
if (!firstRunDone) {
DEBUG_PRINTF("[%s] First run, nothing to do\n", _name);
}
// Check if mod has been en-/disabled
else if (enabled != oldEnabled) {
enabled ? setup() : cleanup();
DEBUG_PRINTF("[%s] Usermod has been en-/disabled\n", _name);
}
// Config has been changed, so adopt to changes
else if (enabled) {
if (oldShtType != shtType) {
cleanupShtTempHumiditySensor();
initShtTempHumiditySensor();
}
if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) {
publishHomeAssistantAutodiscovery();
}
DEBUG_PRINTF("[%s] Config (re)loaded\n", _name);
}
return true;
}
/**
* Adds the temperature and humidity actually to the info section and /json info.
*
* This is called every time the info section is opened ot /json is called.
*
* @see Usermod::addToJsonInfo()
* @see UsermodManager::addToJsonInfo()
*
* @return void
*/
void ShtUsermod::addToJsonInfo(JsonObject& root)
{
if (!enabled && !isShtReady()) {
return;
}
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray jsonTemp = user.createNestedArray(F("Temperature"));
JsonArray jsonHumidity = user.createNestedArray(F("Humidity"));
if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) {
jsonTemp.add(0);
jsonHumidity.add(0);
if (shtLastTimeUpdated == 0) {
jsonTemp.add(F(" Not read yet"));
jsonHumidity.add(F(" Not read yet"));
}
else {
jsonTemp.add(F(" Error"));
jsonHumidity.add(F(" Error"));
}
return;
}
jsonHumidity.add(shtCurrentHumidity);
jsonHumidity.add(F(" RH"));
unitOfTemp ? jsonTemp.add(getTemperatureF()) : jsonTemp.add(getTemperatureC());
unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C"));
}
/**
* Getter for last read temperature in Celsius.
*
* @return float
*/
float ShtUsermod::getTemperatureC() {
return shtCurrentTempC;
}
/**
* Getter for last read temperature in Fahrenheit.
*
* @return float
*/
float ShtUsermod::getTemperatureF() {
return shtCurrentTempF;
}
/**
* Getter for last read humidity in RH%.
*
* @return float
*/
float ShtUsermod::getHumidity() {
return shtCurrentHumidity;
}

View File

@@ -373,9 +373,10 @@ typedef struct Segment {
uint32_t call; // call counter
uint16_t aux0; // custom var
uint16_t aux1; // custom var
byte* data;
CRGB* leds;
static CRGB *_globalLeds;
byte* data; // effect data pointer
CRGB* leds; // local leds[] array (may be a pointer to global)
static CRGB *_globalLeds; // global leds[] array
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
void *jMap; //WLEDMM jMap
private:
@@ -667,8 +668,6 @@ class WS2812FX { // 96 bytes
vPanels(1),
panelH(8),
panelW(8),
matrixWidth(DEFAULT_LED_COUNT),
matrixHeight(1),
matrix{0,0,0,0},
panel{{0,0,0,0}},
#endif
@@ -824,9 +823,7 @@ class WS2812FX { // 96 bytes
uint16_t
panelH,
panelW,
matrixWidth,
matrixHeight;
panelW;
typedef struct panel_bitfield_t {
bool bottomStart : 1; // starts at bottom?

View File

@@ -29,8 +29,8 @@
// setUpMatrix() - constructs ledmap array from matrix of panels with WxH pixels
// this converts physical (possibly irregular) LED arrangement into well defined
// array of logical pixels: fist entry corresponds to left-topmost logical pixel
// followed by horizontal pixels, when matrixWidth logical pixels are added they
// are followed by next row (down) of matrixWidth pixels (and so forth)
// followed by horizontal pixels, when Segment::maxWidth logical pixels are added they
// are followed by next row (down) of Segment::maxWidth pixels (and so forth)
// note: matrix may be comprised of multiple panels each with different orientation
// but ledmap takes care of that. ledmap is constructed upon initialization
// so matrix should disable regular ledmap processing
@@ -43,20 +43,21 @@ void WS2812FX::setUpMatrix(bool reset) {
customMappingSize = 0;
}
// isMatrix is set in cfg.cpp or set.cpp
if (isMatrix) {
matrixWidth = hPanels * panelW;
matrixHeight = vPanels * panelH;
Segment::maxWidth = hPanels * panelW;
Segment::maxHeight = vPanels * panelH;
// safety check
if (matrixWidth * matrixHeight > MAX_LEDS) {
matrixWidth = _length;
matrixHeight = 1;
if (Segment::maxWidth * Segment::maxHeight > MAX_LEDS || Segment::maxWidth == 1 || Segment::maxHeight == 1) {
Segment::maxWidth = _length;
Segment::maxHeight = 1;
isMatrix = false;
return;
}
if (reset) { //WLEDMM: add reset option to switch on/off reset of customMappingTable
customMappingSize = matrixWidth * matrixHeight;
customMappingSize = Segment::maxWidth * Segment::maxHeight;
customMappingTable = new uint16_t[customMappingSize];
//WLEDMM: init customMappingTable with a 1:1 mapping (for customMappingTable[customMappingTable[x]])
for (uint16_t i=0; i<customMappingSize; i++) {
@@ -77,7 +78,7 @@ void WS2812FX::setUpMatrix(bool reset) {
x = (matrix.vertical ? matrix.bottomStart : matrix.rightStart) ? h - i - 1 : i;
x = matrix.serpentine && j%2 ? h - x - 1 : x;
startL = (matrix.vertical ? y : x) * panelW + (matrix.vertical ? x : y) * matrixWidth * panelH; // logical index (top-left corner)
startL = (matrix.vertical ? y : x) * panelW + (matrix.vertical ? x : y) * Segment::maxWidth * panelH; // logical index (top-left corner)
startP = p * panelW * panelH; // physical index (top-left corner)
uint8_t H = panel[h*j + i].vertical ? panelW : panelH;
@@ -87,7 +88,7 @@ void WS2812FX::setUpMatrix(bool reset) {
y = (panel[h*j + i].vertical ? panel[h*j + i].rightStart : panel[h*j + i].bottomStart) ? H - l - 1 : l;
x = (panel[h*j + i].vertical ? panel[h*j + i].bottomStart : panel[h*j + i].rightStart) ? W - k - 1 : k;
x = (panel[h*j + i].serpentine && l%2) ? (W - x - 1) : x;
offset = (panel[h*j + i].vertical ? y : x) + (panel[h*j + i].vertical ? x : y) * matrixWidth;
offset = (panel[h*j + i].vertical ? y : x) + (panel[h*j + i].vertical ? x : y) * Segment::maxWidth;
customMappingTable[customMappingTable[startL + offset]] = startP + q; //WLEDMM: allow for 2 transitions if reset = false (ledmap and logical to physical)
}
}
@@ -96,22 +97,22 @@ void WS2812FX::setUpMatrix(bool reset) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("Matrix ledmap:"));
for (uint16_t i=0; i<customMappingSize; i++) {
if (!(i%matrixWidth)) DEBUG_PRINTLN();
if (!(i%Segment::maxWidth)) DEBUG_PRINTLN();
DEBUG_PRINTF("%4d,", customMappingTable[i]);
}
DEBUG_PRINTLN();
#endif
} else {
// memory allocation error
matrixWidth = _length;
matrixHeight = 1;
Segment::maxWidth = _length;
Segment::maxHeight = 1;
isMatrix = false;
return;
}
} else {
// not a matrix set up
matrixWidth = _length;
matrixHeight = 1;
Segment::maxWidth = _length;
Segment::maxHeight = 1;
}
#endif
}
@@ -121,7 +122,7 @@ void IRAM_ATTR_YN WS2812FX::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM
{
#ifndef WLED_DISABLE_2D
if (!isMatrix) return; // not a matrix set-up
uint16_t index = y * matrixWidth + x;
uint16_t index = y * Segment::maxWidth + x;
if (index >= customMappingSize) return; // customMappingSize is always W * H of matrix in 2D setup
#else
uint16_t index = x;
@@ -134,7 +135,7 @@ void IRAM_ATTR_YN WS2812FX::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM
// returns RGBW values of pixel
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
#ifndef WLED_DISABLE_2D
uint16_t index = (y * matrixWidth + x);
uint16_t index = (y * Segment::maxWidth + x);
if (index >= customMappingSize) return 0; // customMappingSize is always W * H of matrix in 2D setup
#else
uint16_t index = x;
@@ -159,7 +160,7 @@ uint16_t IRAM_ATTR_YN Segment::XY(uint16_t x, uint16_t y) { //WLEDMM: IRAM_ATTR
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionaly
{
if (!strip.isMatrix) return; // not a matrix set-up
if (Segment::maxHeight==1) return; // not a matrix set-up
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
if (leds) leds[XY(x,y)] = col;
@@ -206,7 +207,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM:
// anti-aliased version of setPixelColorXY()
void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
{
if (!strip.isMatrix) return; // not a matrix set-up
if (Segment::maxHeight==1) return; // not a matrix set-up
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
const uint16_t cols = virtualWidth();

View File

@@ -75,6 +75,8 @@
///////////////////////////////////////////////////////////////////////////////
uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
CRGB *Segment::_globalLeds = nullptr;
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
uint16_t Segment::maxHeight = 1;
// copy constructor
Segment::Segment(const Segment &orig) {
@@ -196,7 +198,7 @@ void Segment::setUpLeds() {
// deallocation happens in resetIfRequired() as it is called when segment changes or in destructor
if (Segment::_globalLeds)
#ifndef WLED_DISABLE_2D
leds = &Segment::_globalLeds[start + startY*strip.matrixWidth]; // TODO: remove this hack
leds = &Segment::_globalLeds[start + startY*Segment::maxWidth];
#else
leds = &Segment::_globalLeds[start];
#endif
@@ -699,7 +701,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
if (i >= virtualLength() || i<0) return; // if pixel would fall out of segment just exit
#ifndef WLED_DISABLE_2D
if (is2D()) { // if this does not work use strip.isMatrix
if (is2D()) {
uint16_t vH = virtualHeight(); // segment height in logical pixels
uint16_t vW = virtualWidth();
switch (map1D2D) {
@@ -758,7 +760,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
break;
}
return;
} else if (strip.isMatrix && (width()==1 || height()==1)) { // TODO remove this hack
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) {
// we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed)
int x = 0, y = 0;
if (virtualHeight()>1) y = i;
@@ -846,7 +848,7 @@ uint32_t Segment::getPixelColor(int i)
i &= 0xFFFF;
#ifndef WLED_DISABLE_2D
if (is2D()) { // if this does not work use strip.isMatrix
if (is2D()) {
uint16_t vH = virtualHeight(); // segment height in logical pixels
uint16_t vW = virtualWidth();
switch (map1D2D) {
@@ -1609,6 +1611,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
// disabled segments should get removed using purgeSegments()
DEBUG_PRINT(F("-- Segment ")); DEBUG_PRINT(n); DEBUG_PRINTLN(F(" marked inactive."));
seg.stop = 0;
seg.options = 0b0000000000000101; // on & selected
//if (seg.name) {
// delete[] seg.name;
// seg.name = nullptr;
@@ -1620,10 +1623,10 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
}
if (isMatrix) {
#ifndef WLED_DISABLE_2D
if (i1 < matrixWidth) seg.start = i1;
seg.stop = i2 > matrixWidth ? matrixWidth : i2;
if (startY < matrixHeight) seg.startY = startY;
seg.stopY = stopY > matrixHeight ? matrixHeight : MAX(1,stopY);
if (i1 < Segment::maxWidth) seg.start = i1;
seg.stop = i2 > Segment::maxWidth ? Segment::maxWidth : i2;
if (startY < Segment::maxHeight) seg.startY = startY;
seg.stopY = stopY > Segment::maxHeight ? Segment::maxHeight : MAX(1,stopY);
if (Segment::_globalLeds) seg.setUpLeds(); //WLEDMM force all effects to use globalleds
#endif
} else {
@@ -1648,7 +1651,7 @@ void WS2812FX::restartRuntime() {
void WS2812FX::resetSegments() {
_segments.clear(); // destructs all Segment as part of clearing
#ifndef WLED_DISABLE_2D
segment seg = isMatrix ? Segment(0, matrixWidth, 0, matrixHeight) : Segment(0, _length);
segment seg = isMatrix ? Segment(0, Segment::maxWidth, 0, Segment::maxHeight) : Segment(0, _length);
#else
segment seg = Segment(0, _length);
#endif
@@ -1664,9 +1667,9 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
else if (getActiveSegmentsNum() == 1) {
size_t i = getLastActiveSegmentId();
_segments[i].start = 0;
_segments[i].stop = matrixWidth;
_segments[i].stop = Segment::maxWidth;
_segments[i].startY = 0;
_segments[i].stopY = matrixHeight;
_segments[i].stopY = Segment::maxHeight;
_segments[i].grouping = 1;
_segments[i].spacing = 0;
_mainSegment = i;
@@ -1862,7 +1865,7 @@ void WS2812FX::deserializeMap(uint8_t n) {
//WLEDMM: if isMatrix then customMap size is whole matrix
#ifndef WLED_DISABLE_2D
if (isMatrix)
customMappingSize = matrixWidth * matrixHeight;
customMappingSize = Segment::maxWidth * Segment::maxHeight;
else
#endif
customMappingSize = map.size();

View File

@@ -100,10 +100,11 @@
#define USERMOD_ID_BOBLIGHT 36 //Usermod "boblight.h"
#define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h"
#define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h
#define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h
//WLEDMM
#define USERMOD_ID_CUSTOMEFFECTS 39 //Usermod "usermod_v2_customeffects.h"
#define USERMOD_ID_WEATHER 40 //Usermod "usermod_v2_weather.h"
#define USERMOD_ID_GAMES 41 //Usermod "usermod_v2_games.h"
#define USERMOD_ID_CUSTOMEFFECTS 90 //Usermod "usermod_v2_customeffects.h"
#define USERMOD_ID_WEATHER 91 //Usermod "usermod_v2_weather.h"
#define USERMOD_ID_GAMES 92 //Usermod "usermod_v2_games.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
@@ -396,12 +397,22 @@
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
// 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)
#if defined(I2CSCLPIN) && !defined(HW_PIN_SCL)
#define HW_PIN_SCL I2CSCLPIN
#endif
#if defined(I2CSDAPIN) && !defined(HW_PIN_SDA)
#define HW_PIN_SDA I2CSDAPIN
#endif
// you cannot change HW I2C pins on 8266
#if defined(ESP8266) && defined(HW_PIN_SCL)
#undef HW_PIN_SCL
#endif
#if defined(ESP8266) && defined(HW_PIN_SDA)
#undef HW_PIN_SDA
#endif
// defaults for 1st I2C on ESP32 (Wire global)
#ifndef HW_PIN_SCL
#define HW_PIN_SCL SCL
#endif
@@ -409,6 +420,18 @@
#define HW_PIN_SDA SDA
#endif
// HW_PIN_SCLKSPI & HW_PIN_MOSISPI & HW_PIN_MISOSPI are used for information in usermods settings page and usermods themselves
// which GPIO pins are actually used in a hardwarea layout (controller board)
#if defined(SPISCLKPIN) && !defined(HW_PIN_CLOCKSPI)
#define HW_PIN_CLOCKSPI SPISCLKPIN
#endif
#if defined(SPIMOSIPIN) && !defined(HW_PIN_MOSISPI)
#define HW_PIN_MOSISPI SPIMOSIPIN
#endif
#if defined(SPIMISOPIN) && !defined(HW_PIN_MISOSPI)
#define HW_PIN_MISOSPI SPIMISOPIN
#endif
// you cannot change HW SPI pins on 8266
#if defined(ESP8266) && defined(HW_PIN_CLOCKSPI)
#undef HW_PIN_CLOCKSPI
#endif
@@ -418,10 +441,7 @@
#if defined(ESP8266) && defined(HW_PIN_MISOSPI)
#undef HW_PIN_MISOSPI
#endif
#if defined(ESP8266) && defined(HW_PIN_CSSPI)
#undef HW_PIN_CSSPI
#endif
// defaults for VSPI
// defaults for VSPI on ESP32 (SPI global, SPI.cpp) as HSPI is used by WLED (bus_wrapper.h)
#ifndef HW_PIN_CLOCKSPI
#define HW_PIN_CLOCKSPI SCK
#endif
@@ -431,9 +451,6 @@
#ifndef HW_PIN_MISOSPI
#define HW_PIN_MISOSPI MISO
#endif
#ifndef HW_PIN_CSSPI
#define HW_PIN_CSSPI SS
#endif
// WLEDMM: IRAM_ATTR for 8266 causes error: section `.text1' will not fit in region `iram1_0_seg'
// error only in MM, not in upstream... tbd: find out why

View File

@@ -128,12 +128,13 @@ button {
display: inline-block;
}
.icons.on {
color: var(--c-g);
.on {
color: var(--c-g) !important;
}
.icons.off {
color: var(--c-6);
.off {
color: var(--c-6) !important;
cursor: default !important;
}
.top .icons, .bot .icons {
@@ -981,7 +982,7 @@ textarea {
.segname, .pname {
white-space: nowrap;
cursor: pointer;
/*cursor: pointer;*/
text-align: center;
overflow: clip;
text-overflow: ellipsis;

View File

@@ -1,6 +1,5 @@
//page js
var loc = false, locip;
var noNewSegs = false;
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
var hasWhite = false, hasRGB = false, hasCCT = false;
var nlDur = 60, nlTar = 0;
@@ -819,18 +818,14 @@ function populateSegments(s)
}
gId('segcont').innerHTML = cn;
if (lowestUnused >= maxSeg) {
gId('segutil').innerHTML = '<span class="h">Maximum number of segments reached.</span>';
noNewSegs = true;
} else if (noNewSegs) {
resetUtil();
noNewSegs = false;
}
let noNewSegs = (lowestUnused >= maxSeg);
resetUtil(noNewSegs);
if (gId('selall')) gId('selall').checked = true;
for (var i = 0; i <= lSeg; i++) {
updateLen(i);
updateTrail(gId(`seg${i}bri`));
gId(`segr${i}`).style.display = "none";
if (!gId(`seg${i}sel`).checked) gId(`selall`).checked = false;
if (!gId(`seg${i}sel`).checked && gId('selall')) gId('selall').checked = false; // uncheck if at least one is unselected.
}
if (segCount < 2) gId(`segd${lSeg}`).style.display = "none";
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline";
@@ -1719,15 +1714,15 @@ function makeSeg()
gId('segutil').innerHTML = cn;
}
function resetUtil()
function resetUtil(off=false)
{
// gId('segutil').innerHTML = '<button class="btn btn-s" onclick="makeSeg()"><i class="icons btn-icon">&#xe18a;</i>segment</button>';
gId('segutil').innerHTML = '<div class="seg btn btn-s" style="border-radius:24px;padding:0;">'
gId('segutil').innerHTML = `<div class="seg btn btn-s ${off?'off':''}" style="border-radius:24px;padding:0;">`
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark"></span></label>'
+ '<div class="segname" onclick="makeSeg()"><i class="icons btn-icon">&#xe18a;</i>Add segment</div></div>';
+ `<div class="segname" ${off?'':'onclick="makeSeg()"'}><i class="icons btn-icon">&#xe18a;</i>Add segment</div></div>`;
}
function makePlSel(el, incPl=false) {
function makePlSel(el, incPl=false)
{
var plSelContent = "";
delete pJson["0"]; // remove filler preset
var arr = Object.entries(pJson);
@@ -1739,7 +1734,8 @@ function makePlSel(el, incPl=false) {
return plSelContent;
}
function refreshPlE(p) {
function refreshPlE(p)
{
var plEDiv = gId(`ple${p}`);
if (!plEDiv) return;
var content = "<div class=\"first c\">Playlist entries</div>";
@@ -1761,14 +1757,16 @@ function refreshPlE(p) {
}
// p: preset ID, i: ps index
function addPl(p,i) {
function addPl(p,i)
{
plJson[p].ps.splice(i+1,0,0);
plJson[p].dur.splice(i+1,0,plJson[p].dur[i]);
plJson[p].transition.splice(i+1,0,plJson[p].transition[i]);
refreshPlE(p);
}
function delPl(p,i) {
function delPl(p,i)
{
if (plJson[p].ps.length < 2) return;
plJson[p].ps.splice(i,1);
plJson[p].dur.splice(i,1);
@@ -1776,21 +1774,25 @@ function delPl(p,i) {
refreshPlE(p);
}
function plePs(p,i,field) {
function plePs(p,i,field)
{
plJson[p].ps[i] = parseInt(field.value);
}
function pleDur(p,i,field) {
function pleDur(p,i,field)
{
if (field.validity.valid)
plJson[p].dur[i] = Math.floor(field.value*10);
}
function pleTr(p,i,field) {
function pleTr(p,i,field)
{
if (field.validity.valid)
plJson[p].transition[i] = Math.floor(field.value*10);
}
function plR(p) {
function plR(p)
{
var pl = plJson[p];
pl.r = gId(`pl${p}rtgl`).checked;
if (gId(`pl${p}rptgl`).checked) { // infinite
@@ -1804,7 +1806,8 @@ function plR(p) {
}
}
function makeP(i,pl) {
function makeP(i,pl)
{
var content = "";
if (pl) {
if (i===0) plJson[0] = {
@@ -1988,7 +1991,7 @@ function selSegAll(o)
function selSegEx(s)
{
gId(`selall`).checked = false;
if (gId('selall')) gId('selall').checked = false;
var obj = {"seg":[]};
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
obj.mainseg = s;
@@ -1997,7 +2000,7 @@ function selSegEx(s)
function selSeg(s)
{
gId(`selall`).checked = false;
if (gId('selall')) gId('selall').checked = false;
var sel = gId(`seg${s}sel`).checked;
var obj = {"seg": {"id": s, "sel": sel}};
requestJson(obj);

View File

@@ -44,7 +44,7 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
const uint16_t PAGE_update_length = 602;
const uint8_t PAGE_update[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x75, 0x53, 0xd1, 0x6e, 0xd3, 0x30,
0x14, 0x7d, 0xcf, 0x57, 0x78, 0x7e, 0x6a, 0x25, 0x66, 0x0f, 0xc4, 0x0b, 0x23, 0xc9, 0x50, 0xd9,
0x14, 0x7d, 0xcf, 0x57, 0x78, 0x7e, 0x6a, 0x25, 0x66, 0x33, 0xc4, 0x0b, 0x23, 0xc9, 0x50, 0xd9,
0x84, 0x90, 0x98, 0x36, 0x69, 0x1b, 0x88, 0x27, 0xe4, 0xc4, 0x37, 0x8d, 0xa9, 0x63, 0x67, 0xf6,
0x4d, 0xab, 0x0a, 0xed, 0xdf, 0xb9, 0x76, 0xda, 0x81, 0x34, 0x78, 0x89, 0xea, 0xf8, 0xdc, 0x93,
0x73, 0xcf, 0x39, 0x2d, 0x4f, 0x2e, 0x6f, 0x3e, 0xde, 0x7f, 0xbf, 0xbd, 0x62, 0x3d, 0x0e, 0xb6,
@@ -65,8 +65,8 @@ const uint8_t PAGE_update[] PROGMEM = {
0xc3, 0xc0, 0x28, 0x93, 0xde, 0xd3, 0xec, 0xed, 0xcd, 0xdd, 0x3d, 0x67, 0x2a, 0xdb, 0x44, 0x22,
0xa7, 0x8c, 0xe3, 0xcc, 0xd0, 0x15, 0xf9, 0xc2, 0x0a, 0x20, 0x07, 0xf7, 0x23, 0x85, 0x33, 0x4c,
0x16, 0xcd, 0xa8, 0x02, 0xca, 0x34, 0x7f, 0x4a, 0x30, 0xc5, 0x49, 0x41, 0x9c, 0x9a, 0xc1, 0x50,
0xaa, 0x0f, 0x59, 0x40, 0x1c, 0x95, 0x63, 0xad, 0x55, 0x31, 0x56, 0x3c, 0x9a, 0x91, 0xd7, 0x67,
0xe2, 0xf5, 0x5b, 0x41, 0x8f, 0x33, 0x5a, 0x80, 0xee, 0x28, 0xd8, 0x26, 0xd4, 0x97, 0x7e, 0x97,
0xaa, 0x0f, 0x59, 0x40, 0x1c, 0x95, 0x63, 0xad, 0x55, 0x31, 0x56, 0x3c, 0x9a, 0x91, 0xd7, 0xaf,
0xc5, 0xd9, 0x5b, 0x41, 0x8f, 0x33, 0x5a, 0x80, 0xee, 0x28, 0xd8, 0x26, 0xd4, 0x97, 0x7e, 0x97,
0x95, 0x33, 0xec, 0x81, 0x59, 0xfa, 0x5e, 0x44, 0x16, 0xc0, 0x82, 0x8a, 0x70, 0xce, 0x4a, 0xc5,
0x8a, 0x3e, 0x40, 0x57, 0xf1, 0x1e, 0x71, 0x8c, 0xe7, 0x52, 0xae, 0x0d, 0xf6, 0x53, 0x23, 0x5a,
0x3f, 0xc8, 0xc3, 0x72, 0x93, 0x85, 0x28, 0xd3, 0x82, 0xf2, 0x30, 0x16, 0x39, 0x43, 0x15, 0x28,
@@ -80,7 +80,7 @@ const uint8_t PAGE_update[] PROGMEM = {
0x5d, 0xea, 0x27, 0xd1, 0xd4, 0x99, 0x9d, 0x4a, 0x27, 0x84, 0x20, 0x70, 0x26, 0xbf, 0xcd, 0xdb,
0x32, 0xed, 0x99, 0xf3, 0x48, 0x59, 0x79, 0x3a, 0xf8, 0x40, 0x5a, 0xbb, 0x00, 0xb1, 0xcf, 0x91,
0x8c, 0x6a, 0x0d, 0xec, 0x7c, 0x59, 0x4a, 0xe2, 0x4b, 0xeb, 0xa6, 0xb2, 0xa5, 0xe6, 0xa5, 0xbf,
0xf4, 0x6f, 0x77, 0x44, 0x10, 0xd1, 0xe8, 0x03, 0x00, 0x00
0xf4, 0x6f, 0x9c, 0xb1, 0xcb, 0xd7, 0xe8, 0x03, 0x00, 0x00
};

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -47,10 +47,10 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
// Serial.printf("before %d: %s %s %s %s\n", id, elem["start"].as<std::string>().c_str(), elem["stop"].as<std::string>().c_str(), elem["startY"].as<std::string>().c_str(), elem["stopY"].as<std::string>().c_str());
if (strip.isMatrix && !elem["start"].isNull() && !elem["stop"].isNull() && elem["startY"].isNull() && elem["stopY"].isNull()) {
uint16_t start1=elem["start"], stop1=elem["stop"];
elem["start"] = start1%strip.matrixWidth;
elem["startY"]= strip.matrixWidth?(start1 / strip.matrixWidth):0;
elem["stop"] = (stop1-1)%strip.matrixWidth + 1;
elem["stopY"]= strip.matrixWidth?((stop1-1) / strip.matrixWidth) + 1:0;
elem["start"] = start1%Segment::maxWidth;
elem["startY"]= Segment::maxWidth?(start1 / Segment::maxWidth):0;
elem["stop"] = (stop1-1)%Segment::maxWidth + 1;
elem["stopY"]= Segment::maxWidth?((stop1-1) / Segment::maxWidth) + 1:0;
// Serial.printf("after %s %s %s %s\n", elem["start"].as<std::string>().c_str(), elem["stop"].as<std::string>().c_str(), elem["startY"].as<std::string>().c_str(), elem["stopY"].as<std::string>().c_str());
}
#endif
@@ -677,8 +677,8 @@ void serializeInfo(JsonObject root)
#ifndef WLED_DISABLE_2D
if (strip.isMatrix) {
JsonObject matrix = leds.createNestedObject("matrix");
matrix["w"] = strip.matrixWidth;
matrix["h"] = strip.matrixHeight;
matrix["w"] = Segment::maxWidth;
matrix["h"] = Segment::maxHeight;
}
#endif

View File

@@ -1,11 +1,12 @@
#include "wled.h"
#ifdef WLED_ENABLE_LOXONE
/*
* Parser for Loxone formats
*/
bool parseLx(int lxValue, byte rgbw[4])
{
#ifdef WLED_ENABLE_LOXONE
DEBUG_PRINT(F("LX: Lox = "));
DEBUG_PRINTLN(lxValue);
@@ -42,7 +43,6 @@ bool parseLx(int lxValue, byte rgbw[4])
rgbw[3] = 0;
return true;
}
#endif
return false;
}
@@ -62,15 +62,10 @@ void parseLxJson(int lxValue, byte segId, bool secondary)
}
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
if (segId == strip.getMainSegmentId()) {
DEBUG_PRINTLN(F("LX: main segment"));
if (secondary) for (byte i = 0; i < 4; i++) colSec[i] = rgbw[i];
else for (byte i = 0; i < 4; i++) col[i] = rgbw[i];
} else {
DEBUG_PRINT(F("LX: segment "));
DEBUG_PRINTLN(segId);
strip.getSegment(segId).setColor(secondary, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
}
DEBUG_PRINT(F("LX: segment "));
DEBUG_PRINTLN(segId);
strip.getSegment(segId).setColor(secondary, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); // legacy values handled as well in json.cpp by stateUpdated()
}
}
#endif

View File

@@ -180,6 +180,9 @@
#include "../usermods/pwm_outputs/usermod_pwm_outputs.h"
#endif
#ifdef USERMOD_SHT
#include "../usermods/sht/usermod_sht.h"
#endif
//WLEDMM Custom Effects
#ifdef USERMOD_CUSTOMEFFECTS
@@ -308,7 +311,7 @@ void registerUsermods()
#ifdef QUINLED_AN_PENTA
usermods.add(new QuinLEDAnPentaUsermod());
#endif
#ifdef USERMOD_WIZLIGHTS
usermods.add(new WizLightsUsermod());
#endif
@@ -357,6 +360,10 @@ void registerUsermods()
usermods.add(new PwmOutputsUsermod());
#endif
#ifdef USERMOD_SHT
usermods.add(new ShtUsermod());
#endif
//WLEDMM Custom Effects
#ifdef USERMOD_CUSTOMEFFECTS
usermods.add(new CustomEffectsUserMod());

View File

@@ -130,7 +130,7 @@
#include "src/dependencies/dmx/ESPDMX.h"
#else //ESP32
#include "src/dependencies/dmx/SparkFunDMX.h"
#endif
#endif
#endif
#include "src/dependencies/e131/ESPAsyncE131.h"
@@ -394,8 +394,8 @@ WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to f
#ifdef ESP8266
WLED_GLOBAL DMXESPSerial dmx;
#else //ESP32
WLED_GLOBAL SparkFunDMX dmx;
#endif
WLED_GLOBAL SparkFunDMX dmx;
#endif
WLED_GLOBAL uint16_t e131ProxyUniverse _INIT(0); // output this E1.31 (sACN) / ArtNet universe via MAX485 (0 = disabled)
#endif
WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes)
@@ -579,7 +579,7 @@ WLED_GLOBAL int16_t currentPlaylist _INIT(-1);
//still used for "PL=~" HTTP API command
WLED_GLOBAL byte presetCycCurr _INIT(0);
WLED_GLOBAL byte presetCycMin _INIT(1);
WLED_GLOBAL byte presetCycMax _INIT(5);
WLED_GLOBAL byte presetCycMax _INIT(5);
// realtime
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
@@ -677,11 +677,37 @@ WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available l
// Usermod manager
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
WLED_GLOBAL int8_t i2c_sda _INIT(-1); // global I2C SDA pin [HW_PIN_SDA] (used for usermods)
WLED_GLOBAL int8_t i2c_scl _INIT(-1); // global I2C SCL pin [HW_PIN_SCL] (used for usermods)
WLED_GLOBAL int8_t spi_mosi _INIT(-1); // global SPI DATA/MOSI pin [HW_PIN_DATASPI] (used for usermods)
WLED_GLOBAL int8_t spi_miso _INIT(-1); // global SPI DATA/MISO pin [HW_PIN_MISOSPI] (used for usermods)
WLED_GLOBAL int8_t spi_sclk _INIT(-1); // global SPI CLOCK/SCLK pin [HW_PIN_CLOCKSPI] (used for usermods)
// global I2C SDA pin (used for usermods)
#ifndef I2CSDAPIN
WLED_GLOBAL int8_t i2c_sda _INIT(-1);
#else
WLED_GLOBAL int8_t i2c_sda _INIT(I2CSDAPIN);
#endif
// global I2C SCL pin (used for usermods)
#ifndef I2CSCLPIN
WLED_GLOBAL int8_t i2c_scl _INIT(-1);
#else
WLED_GLOBAL int8_t i2c_scl _INIT(I2CSCLPIN);
#endif
// global SPI DATA/MOSI pin (used for usermods)
#ifndef SPIMOSIPIN
WLED_GLOBAL int8_t spi_mosi _INIT(-1);
#else
WLED_GLOBAL int8_t spi_mosi _INIT(SPIMOSIPIN);
#endif
// global SPI DATA/MISO pin (used for usermods)
#ifndef SPIMISOPIN
WLED_GLOBAL int8_t spi_miso _INIT(-1);
#else
WLED_GLOBAL int8_t spi_miso _INIT(SPIMISOPIN);
#endif
// global SPI CLOCK/SCLK pin (used for usermods)
#ifndef SPISCLKPIN
WLED_GLOBAL int8_t spi_sclk _INIT(-1);
#else
WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN);
#endif
// global ArduinoJson buffer
WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> doc;

View File

@@ -161,8 +161,8 @@ bool sendLiveLedsWs(uint32_t wsClient)
#ifndef WLED_DISABLE_2D
if (strip.isMatrix) {
buffer[1] = 2; //version
buffer[2] = strip.matrixWidth;
buffer[3] = strip.matrixHeight;
buffer[2] = Segment::maxWidth;
buffer[3] = Segment::maxHeight;
buffer[4] = currentPreset; //WLEDMM
buffer[5] = currentPlaylist; //WLEDMM
}