From 0f2eb283d5c36ad3db3a5e3f8d30d7177666335d Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 1 Jan 2022 22:51:35 +0100 Subject: [PATCH 001/161] [P128] Migrate NeoPixelBuxFX from playground / djcysmic/NeopixelBusFX --- platformio_esp32_envs.ini | 2 +- platformio_esp82xx_base.ini | 2 +- src/_P128_NeoPixelBusFX.ino | 1769 ++++++++++++++++ src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/PluginStructs/P128_data_struct.cpp | 8 + src/src/PluginStructs/P128_data_struct.h | 2203 ++++++++++++++++++++ 6 files changed, 3983 insertions(+), 3 deletions(-) create mode 100644 src/_P128_NeoPixelBusFX.ino create mode 100644 src/src/PluginStructs/P128_data_struct.cpp create mode 100644 src/src/PluginStructs/P128_data_struct.h diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 87d78bf85..26a6eb650 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -10,7 +10,7 @@ lib_ignore = ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266H [esp32_common] extends = common, core_esp32_3_3_0 -lib_deps = td-er/ESPeasySerial @ 2.0.8, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ArduinoOTA, ESP32HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library +lib_deps = td-er/ESPeasySerial @ 2.0.8, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ArduinoOTA, ESP32HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library, Makuna/NeoPixelBus lib_ignore = ${esp32_always.lib_ignore}, ESP32_ping, IRremoteESP8266, HeatpumpIR board_build.f_flash = 80000000L board_build.flash_mode = dout diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index 77f8c46bd..9424765b7 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -52,7 +52,7 @@ extends = common board_build.f_cpu = 80000000L build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0 build_unflags = -DDEBUG_ESP_PORT -lib_deps = td-er/ESPeasySerial @ 2.0.8, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, bblanchon/ArduinoJson @ ^6.17.2, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/RABurton ESP8266 Mutex @ ^1.0.2, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ESP8266HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library +lib_deps = td-er/ESPeasySerial @ 2.0.8, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, bblanchon/ArduinoJson @ ^6.17.2, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/RABurton ESP8266 Mutex @ ^1.0.2, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ESP8266HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library, Makuna/NeoPixelBus lib_ignore = ${esp82xx_defaults.lib_ignore}, IRremoteESP8266, HeatpumpIR, LittleFS(esp8266), ServoESP32, TinyWireM board = esp12e monitor_filters = esp8266_exception_decoder diff --git a/src/_P128_NeoPixelBusFX.ino b/src/_P128_NeoPixelBusFX.ino new file mode 100644 index 000000000..eb6abcbd3 --- /dev/null +++ b/src/_P128_NeoPixelBusFX.ino @@ -0,0 +1,1769 @@ +#include "_Plugin_Helper.h" + +#ifdef USES_P128 + +// ####################################################################################################### +// #################################### Plugin 128: NeoPixelBusFX ######################################## +// ####################################################################################################### + +// Changelog: +// 2022-01-01, tonhuisman On request migrated from https://github.com/djcysmic/NeopixelBusFX to ESPEasy (that is an +// extension from plugin _P124_NeoPixelBusFX.ini on the ESPEasyPluginPlayground) +// - Adjusted to work combined with FastLED library (random8() issues) +// - Moved firetv.h data to P128_data_struct.h +// - Use PCONFIG(0) macro where applicable + +/* + List of commands: + + nfx off [fadetime] [delay] + switches the stripe off + + nfx on [fadetime] [delay] + restores last state of the stripe + + nfx dim [dimvalue] + dimvalue 0-255 + + nfx line startpixel endpixel color + nfx hsvline startpixel endpixel hue saturation brightness + + nfx one pixel color + nfx hsvone pixel hue saturation brightness + + nfx all color [fadetime] [delay] + nfx rgb color [fadetime] [delay] + nfx fade color [fadetime] [delay] + + nfx hsv hue saturation brightness [fadetime] [delay] + + nfx colorfade startcolor endcolor [startpixel] [endpixel] + + nfx rainbow [speed] [fadetime] + + nfx kitt color [speed] + + nfx comet color [speed] + + nfx theatre color [backgroundcolor] [count] [speed] + + nfx scan color [backgroundcolor] [speed] + + nfx dualscan color [backgroundcolor] [speed] + + nfx twinkle color [backgroundcolor] [speed] + + nfx twinklefade color [count] [speed] + + nfx sparkle color [backgroundcolor] [speed] + + nfx wipe color [dotcolor] [speed] + + nfx dualwipe [dotcolor] [speed] + + nfx fire [fps] [brightness] [cooling] [sparking] + + nfx fireflicker [intensity] [speed] + + nfx faketv [startpixel] [endpixel] + + nfx simpleclock [bigtickcolor] [smalltickcolor] [hourcolor] [minutecolor] [secondcolor, set "off" to disable] [backgroundcolor] + + + nfx stop + stops the effect + + nfx statusrequest + sends status + + nfx fadetime + nfx fadedelay + nfx speed + nfx count + nfx bgcolor + sets default parameter + + Use: + + needed: + color,backgroundcolor -> targetcolor in hex format e.g. ff0000 for red + + [optional]: + fadetime -> fadetime per pixel in ms + delay -> delay time to next pixel in ms, if delay < 0 fades from other end of the stripe + speed -> 0-50, speed < 0 for reverse + + Sourced from: https://github.com/djcysmic/NeopixelBusFX + + Based on Adafruit Fake TV Light for Engineers, WS2812FX, NeoPixelBus, Lights, NeoPixel - Basic and Candle modules + + https://learn.adafruit.com/fake-tv-light-for-engineers/overview + https://github.com/letscontrolit/ESPEasy + https://github.com/kitesurfer1404/WS2812FX + https://github.com/Makuna/NeoPixelBus + https://github.com/ddtlabs/ESPEasy-Plugin-Lights + + Thank you to all developers + */ + +# include "src/PluginStructs/P128_data_struct.h" // includes faketv.h, the color pattern for FakeTV +# include + +# define SPEED_MAX 50 +# define ARRAYSIZE 300 // Max LED Count + +// Choose your color order below: + +# define GRB // should be standard - SK6812(grb), WS2811, and WS2812 +// # define GRBW //This is used for SK6812rgbw pixels that have the separate white led in them. +// # define RGB //some older pixels +// # define RGBW //A four element color in the order of Red, Green, Blue, and then White. A common four element format. +// # define BRG //A three element color in the order of Blue, Red, and then Green. +// # define RBG //A three element color in the order of Red, Blue, and then Green. + +# define NEOPIXEL_LIB NeoPixelBrightnessBus // Neopixel library type +# ifdef ESP32 +# define METHOD DotStarEsp32DmaHspiMethod // HSPI MOSI - use DotStarEsp32DmaHspiMethod (should also work on ESP32S2) +# elif ESP8266 +# ifdef METHOD +# undef METHOD +# endif // ifdef METHOD +# define METHOD NeoEsp8266Uart1800KbpsMethod // GPIO2 - use NeoEsp8266Uart0800KbpsMethod for GPIO1(TX) +# endif // ifdef ESP32 + +# if defined GRB + # define FEATURE NeoGrbFeature +# elif defined GRBW + # define FEATURE NeoGrbwFeature +# elif defined RGB + # define FEATURE NeoRgbFeature +# elif defined RGBW + # define FEATURE NeoRgbwFeature +# elif defined BRG + # define FEATURE NeoBrgFeature +# elif defined RBG + # define FEATURE NeoRbgFeature +# else // if defined GRB + # define FEATURE NeoGrbFeature +# endif // if defined GRB + +# define numPixels (sizeof(ftv_colors) / sizeof(ftv_colors[0])) + +NEOPIXEL_LIB *Plugin_128_pixels = NULL; + +const float pi = 3.1415926535897932384626433832795; + +uint16_t pos, + color, + r_pixel, + startpixel, + endpixel, + difference, + fps = 50, + colorcount; + +# if defined(RGBW) || defined(GRBW) +RgbwColor rgb_target[ARRAYSIZE], + rgb_old[ARRAYSIZE], + rgb, rrggbb, + rgb_tick_b = HtmlColor(0x505050), + rgb_tick_s = HtmlColor(0x101010), + rgb_m = HtmlColor(0x00FF00), + rgb_h = HtmlColor(0x0000FF), + rgb_s = HtmlColor(0xFF0000); +# else // if defined(RGBW) || defined(GRBW) +RgbColor rgb_target[ARRAYSIZE], + rgb_old[ARRAYSIZE], + rgb, rrggbb, + rgb_tick_b = HtmlColor(0x505050), + rgb_tick_s = HtmlColor(0x101010), + rgb_m = HtmlColor(0x00FF00), + rgb_h = HtmlColor(0x0000FF), + rgb_s = HtmlColor(0xFF0000); +# endif // if defined(RGBW) || defined(GRBW) + +int16_t fadedelay = 20; + +uint16_t pixelCount = ARRAYSIZE; + +int8_t defaultspeed = 25, + rainbowspeed = 1, + speed = 25, + count = 1, + rev_intensity = 3; + +uint32_t _counter_mode_step = 0, + fadetime = 1000, + ftv_holdTime, + pixelNum; + +uint16_t ftv_pr = 0, ftv_pg = 0, ftv_pb = 0; // Prev R, G, B; +uint32_t ftv_totalTime, ftv_fadeTime, ftv_startTime, ftv_elapsed; +uint16_t ftv_nr, ftv_ng, ftv_nb, ftv_r, ftv_g, ftv_b, ftv_i, ftv_frac; +uint8_t ftv_hi, ftv_lo, ftv_r8, ftv_g8, ftv_b8; + +String colorStr, + backgroundcolorStr; + +bool gReverseDirection = false; +bool rgb_s_off = false; +bool fadeIn = false; + +byte cooling = 50, + sparking = 120, + brightness = 31; + +unsigned long counter20ms = 0, + starttime[ARRAYSIZE], + starttimerb, + maxtime = 0; + +enum modetype { + Off, On, Fade, ColorFade, Rainbow, Kitt, Comet, + Theatre, Scan, Dualscan, Twinkle, TwinkleFade, Sparkle, Fire, + FireFlicker, Wipe, Dualwipe, FakeTV, SimpleClock +}; + +const char *modeName[] = { + "off", "on", "fade", "colorfade", "rainbow", "kitt", "comet", + "theatre", "scan", "dualscan", "twinkle", "twinklefade", "sparkle", "fire", + "fireflicker", "wipe", "dualwipe", "faketv", "simpleclock" +}; + +modetype mode, savemode, lastmode; + +# define PLUGIN_128 +# define PLUGIN_ID_128 128 +# define PLUGIN_NAME_128 "Output - NeoPixel (BusFX) [DEVELOPMENT]" +# define PLUGIN_VALUENAME1_128 "Mode" +# define PLUGIN_VALUENAME2_128 "Lastmode" +# define PLUGIN_VALUENAME3_128 "Fadetime" +# define PLUGIN_VALUENAME4_128 "Fadedelay" + +boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) +{ + boolean success = false; + + switch (function) + { + case PLUGIN_DEVICE_ADD: + { + Device[++deviceCount].Number = PLUGIN_ID_128; + Device[deviceCount].Type = DEVICE_TYPE_DUMMY; + Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_QUAD; + Device[deviceCount].Custom = true; + Device[deviceCount].Ports = 0; + Device[deviceCount].PullUpOption = false; + Device[deviceCount].InverseLogicOption = false; + Device[deviceCount].FormulaOption = false; + Device[deviceCount].ValueCount = 4; + Device[deviceCount].SendDataOption = true; + Device[deviceCount].TimerOption = true; + Device[deviceCount].TimerOptional = true; + Device[deviceCount].GlobalSyncOption = true; + Device[deviceCount].DecimalsOnly = false; + break; + } + + case PLUGIN_GET_DEVICENAME: + { + string = F(PLUGIN_NAME_128); + break; + } + + case PLUGIN_GET_DEVICEVALUENAMES: + { + strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_128)); + strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_128)); + strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_128)); + strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_128)); + break; + } + + case PLUGIN_WEBFORM_LOAD: + { + addRowLabel(F("")); + String message = F("Please connect stripe to "); + # ifdef ESP32 + message += F("HSPI MOSI!"); + # elif ESP8266 + message += F("GPIO2!"); + # endif // ifdef ESP32 + addHtml(message); + addFormNumericBox(F("Led Count"), F("plugin_128_leds"), PCONFIG(0), 1, 999); + success = true; + break; + } + + case PLUGIN_WEBFORM_SAVE: + { + PCONFIG(0) = getFormItemInt(F("plugin_128_leds")); + + // Settings.TaskDevicePin1[event->TaskIndex] = getFormItemInt(F("taskdevicepin1")); + + success = true; + break; + } + + case PLUGIN_INIT: + { + if (!Plugin_128_pixels) { + # ifdef ESP8266 + Plugin_128_pixels = new NEOPIXEL_LIB(PCONFIG(0)); + # endif // ifdef ESP8266 + # ifdef ESP32 + Plugin_128_pixels = new NEOPIXEL_LIB(PCONFIG(0)); + # endif // ifdef ESP32 + Plugin_128_pixels->Begin(); // This initializes the NeoPixelBus library. + } + + pixelCount = PCONFIG(0); + success = true; + break; + } + + case PLUGIN_READ: // -------------------------------------------> + { + // there is no need to read them, just use current values + UserVar[event->BaseVarIndex] = mode; + UserVar[event->BaseVarIndex + 1] = savemode; + UserVar[event->BaseVarIndex + 2] = fadetime; + UserVar[event->BaseVarIndex + 3] = fadedelay; + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log = F("Lights: mode: "); + log += modeName[mode]; + log += F(" lastmode: "); + log += modeName[savemode]; + log += F(" fadetime: "); + log += (int)UserVar[event->BaseVarIndex + 2]; + log += F(" fadedelay: "); + log += (int)UserVar[event->BaseVarIndex + 3]; + addLog(LOG_LEVEL_INFO, log); + } + + success = true; + break; + } + + case PLUGIN_WRITE: + { + String log = ""; + String command = parseString(string, 1); + + if ((command == F("neopixelfx")) || (command == F("nfx"))) { + success = true; + String subCommand = parseString(string, 2); + + if (subCommand == F("fadetime")) { + fadetime = parseString(string, 3).toInt(); + } + + else if (subCommand == F("fadedelay")) { + fadedelay = parseString(string, 3).toInt(); + } + + else if (subCommand == F("speed")) { + defaultspeed = parseString(string, 3).toInt(); + speed = defaultspeed; + } + + else if (subCommand == F("bgcolor")) { + hex2rrggbb(parseString(string, 3)); + } + + else if (subCommand == F("count")) { + count = parseString(string, 3).toInt(); + } + + else if ((subCommand == F("on")) || (subCommand == F("off"))) { + fadetime = 1000; + fadedelay = 0; + + fadetime = (parseString(string, 3) == "") + ? fadetime + : parseString(string, 3).toInt(); + fadedelay = (parseString(string, 4) == "") + ? fadedelay + : parseString(string, 4).toInt(); + + for (int pixel = 0; pixel < pixelCount; pixel++) { + r_pixel = (fadedelay < 0) + ? pixelCount - pixel - 1 + : pixel; + + starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); + + if ((subCommand == F("on")) && (mode == Off)) { // switch on + rgb_target[pixel] = rgb_old[pixel]; + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + } else if (subCommand == F("off")) { // switch off + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + rgb_target[pixel] = RgbColor(0); + } + } + + if ((subCommand == F("on")) && (mode == Off)) { // switch on + mode = (savemode == On) ? Fade : savemode; + } else if (subCommand == F("off")) { // switch off + savemode = mode; + mode = Fade; + } + + maxtime = starttime[r_pixel] + (fadetime / 20); + } + + else if (subCommand == F("dim")) { + Plugin_128_pixels->SetBrightness(parseString(string, 3).toInt()); + } + + else if (subCommand == F("line")) { + mode = On; + + hex2rgb(parseString(string, 5)); + + for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { + Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); + } + } + + else if (subCommand == F("tick")) { + mode = On; + + hex2rgb(parseString(string, 4)); + + // for (int i = 0; i < pixelCount ; i = i + (pixelCount / parseString(string, 3).toInt())) { + for (int i = 0; i < parseString(string, 3).toInt(); i++) { + Plugin_128_pixels->SetPixelColor(i * pixelCount / parseString(string, 3).toInt(), rgb); + } + } + + else if (subCommand == F("one")) { + mode = On; + + uint16_t pixnum = parseString(string, 3).toInt() - 1; + hex2rgb(parseString(string, 4)); + + Plugin_128_pixels->SetPixelColor(pixnum, rgb); + } + + else if ((subCommand == F("fade")) || (subCommand == F("all")) || (subCommand == F("rgb"))) { + mode = Fade; + + if ((subCommand == F("all")) || (subCommand == F("rgb"))) { + fadedelay = 0; + } + + hex2rgb(parseString(string, 3)); + hex2rgb_pixel(parseString(string, 3)); + + fadetime = (parseString(string, 4) == "") + ? fadetime + : parseString(string, 4).toInt(); + fadedelay = (parseString(string, 5) == "") + ? fadedelay + : parseString(string, 5).toInt(); + + for (int pixel = 0; pixel < pixelCount; pixel++) { + r_pixel = (fadedelay < 0) + ? pixelCount - pixel - 1 + : pixel; + + starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); + + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + } + maxtime = starttime[r_pixel] + (fadetime / 20); + } + + else if (subCommand == F("hsv")) { + mode = Fade; + fadedelay = 0; + rgb = + RgbColor(HsbColor(parseString(string, 3).toFloat() / 360, parseString(string, 4).toFloat() / 100, + parseString(string, 5).toFloat() / 100)); + + colorStr = ""; + rgb.R < 16 ? colorStr = "0" : ""; + colorStr += formatToHex(rgb.R, {}); + rgb.G < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.G, {}); + rgb.B < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.B, {}); + + hex2rgb_pixel(colorStr); + + fadetime = (parseString(string, 6) == "") + ? fadetime + : parseString(string, 6).toInt(); + fadedelay = (parseString(string, 7) == "") + ? fadedelay + : parseString(string, 7).toInt(); + + for (int pixel = 0; pixel < pixelCount; pixel++) { + r_pixel = (fadedelay < 0) + ? pixelCount - pixel - 1 + : pixel; + + starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); + + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + } + maxtime = starttime[r_pixel] + (fadetime / 20); + } + + else if (subCommand == F("hsvone")) { + mode = On; + rgb = + RgbColor(HsbColor(parseString(string, 4).toFloat() / 360, parseString(string, 5).toFloat() / 100, + parseString(string, 6).toFloat() / 100)); + + colorStr = ""; + rgb.R < 16 ? colorStr = "0" : ""; + colorStr += formatToHex(rgb.R, {}); + rgb.G < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.G, {}); + rgb.B < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.B, {}); + + hex2rgb(colorStr); + uint16_t pixnum = parseString(string, 3).toInt() - 1; + Plugin_128_pixels->SetPixelColor(pixnum, rgb); + } + + else if (subCommand == F("hsvline")) { + mode = On; + + rgb = + RgbColor(HsbColor(parseString(string, 5).toFloat() / 360, parseString(string, 6).toFloat() / 100, + parseString(string, 7).toFloat() / 100)); + + colorStr = ""; + rgb.R < 16 ? colorStr = "0" : ""; + colorStr += formatToHex(rgb.R, {}); + rgb.G < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.G, {}); + rgb.B < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.B, {}); + + hex2rgb(colorStr); + + for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { + Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); + } + } + + else if (subCommand == F("rainbow")) { + fadeIn = (mode == Off) ? true : false; + mode = Rainbow; + starttimerb = counter20ms; + + rainbowspeed = (parseString(string, 3) == "") + ? speed + : parseString(string, 3).toInt(); + + fadetime = (parseString(string, 4) == "") + ? fadetime + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("colorfade")) { + mode = ColorFade; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + startpixel = (parseString(string, 5) == "") + ? 0 + : parseString(string, 5).toInt() - 1; + endpixel = (parseString(string, 6) == "") + ? pixelCount - 1 + : parseString(string, 6).toInt() - 1; + } + + else if (subCommand == F("kitt")) { + mode = Kitt; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + speed = (parseString(string, 4) == "") + ? defaultspeed + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("comet")) { + mode = Comet; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + speed = (parseString(string, 4) == "") + ? defaultspeed + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("theatre")) { + mode = Theatre; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + count = (parseString(string, 5) == "") + ? count + : parseString(string, 5).toInt(); + + speed = (parseString(string, 6) == "") + ? defaultspeed + : parseString(string, 6).toInt(); + + for (int i = 0; i < pixelCount; i++) { + if ((i / count) % 2 == 0) { + Plugin_128_pixels->SetPixelColor(i, rgb); + } else { + Plugin_128_pixels->SetPixelColor(i, rrggbb); + } + } + } + + else if (subCommand == F("scan")) { + mode = Scan; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("dualscan")) { + mode = Dualscan; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("twinkle")) { + mode = Twinkle; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("twinklefade")) { + mode = TwinkleFade; + + hex2rgb(parseString(string, 3)); + + count = (parseString(string, 4) == "") + ? count + : parseString(string, 4).toInt(); + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("sparkle")) { + mode = Sparkle; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + hex2rrggbb(parseString(string, 4)); + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("wipe")) { + mode = Wipe; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { + hex2rrggbb(parseString(string, 4)); + } else { + hex2rrggbb("000000"); + } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("dualwipe")) { + mode = Dualwipe; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { + hex2rrggbb(parseString(string, 4)); + } else { + hex2rrggbb("000000"); + } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("faketv")) { + mode = FakeTV; + _counter_mode_step = 0; + + randomSeed(analogRead(A0)); + pixelNum = random(numPixels); // Begin at random point + + startpixel = (parseString(string, 3) == "") + ? 0 + : parseString(string, 3).toInt() - 1; + endpixel = (parseString(string, 4) == "") + ? pixelCount + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("fire")) { + mode = Fire; + + fps = (parseString(string, 3) == "") + ? fps + : parseString(string, 3).toInt(); + + fps = (fps == 0 || fps > 50) ? 50 : fps; + + brightness = (parseString(string, 4) == "") + ? brightness + : parseString(string, 4).toFloat(); + cooling = (parseString(string, 5) == "") + ? cooling + : parseString(string, 5).toFloat(); + sparking = (parseString(string, 6) == "") + ? sparking + : parseString(string, 6).toFloat(); + } + + else if (subCommand == F("fireflicker")) { + mode = FireFlicker; + + rev_intensity = (parseString(string, 3) == "") + ? rev_intensity + : parseString(string, 3).toInt(); + + speed = (parseString(string, 4) == "") + ? defaultspeed + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("simpleclock")) { + mode = SimpleClock; + + # if defined(RGBW) || defined(GRBW) + + if (parseString(string, 3) != "") { + if (parseString(string, 3).length() <= 6) { + rgb_tick_s = + RgbwColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, + rgbStr2Num(parseString(string, 3))); + } else { + rgb_tick_s = + RgbwColor(rgbStr2Num(parseString(string, 3)) >> 24, + rgbStr2Num(parseString(string, 3)) >> 16, + rgbStr2Num(parseString(string, 3)) >> 8, + rgbStr2Num(parseString(string, 3))); + } + } + + if (parseString(string, 4) != "") { + if (parseString(string, 4).length() <= 6) { + rgb_tick_b = + RgbwColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, + rgbStr2Num(parseString(string, 4))); + } else { + rgb_tick_b = + RgbwColor(rgbStr2Num(parseString(string, 4)) >> 24, + rgbStr2Num(parseString(string, 4)) >> 16, + rgbStr2Num(parseString(string, 4)) >> 8, + rgbStr2Num(parseString(string, 4))); + } + } + + if (parseString(string, 5) != "") { + if (parseString(string, 5).length() <= 6) { + rgb_h = + RgbwColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, + rgbStr2Num(parseString(string, 5))); + } else { + rgb_h = + RgbwColor(rgbStr2Num(parseString(string, 5)) >> 24, + rgbStr2Num(parseString(string, 5)) >> 16, + rgbStr2Num(parseString(string, 5)) >> 8, + rgbStr2Num(parseString(string, 5))); + } + } + + if (parseString(string, 6) != "") { + if (parseString(string, 6).length() <= 6) { + rgb_m = + RgbwColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, + rgbStr2Num(parseString(string, 6))); + } else { + rgb_m = + RgbwColor(rgbStr2Num(parseString(string, 6)) >> 24, + rgbStr2Num(parseString(string, 6)) >> 16, + rgbStr2Num(parseString(string, 6)) >> 8, + rgbStr2Num(parseString(string, 6))); + } + } + + if (parseString(string, 7) != "") { + if (parseString(string, 7) == "off") { + rgb_s_off = true; + } else if (parseString(string, 7).length() <= 6) { + rgb_s_off = false; + rgb_s = + RgbwColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, + rgbStr2Num(parseString(string, 7))); + } else { + rgb_s_off = false; + rgb_s = + RgbwColor(rgbStr2Num(parseString(string, 7)) >> 24, + rgbStr2Num(parseString(string, 7)) >> 16, + rgbStr2Num(parseString(string, 7)) >> 8, + rgbStr2Num(parseString(string, 7))); + } + } + + if (parseString(string, 8) != "") { + hex2rrggbb(parseString(string, 8)); + } + + # else // if defined(RGBW) || defined(GRBW) + + rgb_tick_s = (parseString(string, 3) == "") + ? rgb_tick_s + : RgbColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, rgbStr2Num(parseString(string, 3))); + rgb_tick_b = (parseString(string, 4) == "") + ? rgb_tick_b + : RgbColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, rgbStr2Num(parseString(string, 4))); + rgb_h = (parseString(string, 5) == "") + ? rgb_h + : RgbColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, rgbStr2Num(parseString(string, 5))); + rgb_m = (parseString(string, 6) == "") + ? rgb_m + : RgbColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, rgbStr2Num(parseString(string, 6))); + + if (parseString(string, 7) != "") { + if (parseString(string, 7) == "off") { + rgb_s_off = true; + } else { + rgb_s_off = false; + rgb_s = + RgbColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, + rgbStr2Num(parseString(string, 7))); + } + } + + if (parseString(string, 8) != "") { hex2rrggbb(parseString(string, 8)); } + + # endif // if defined(RGBW) || defined(GRBW) + } + + else if (subCommand == F("stop")) { + mode = On; + } + + else if (subCommand == F("statusrequest")) {} + + else if ((subCommand != F("all")) && (subCommand != F("line")) + && (subCommand != F("one")) && (subCommand != F("fade")) + && (subCommand != F("dim")) && (subCommand != F("fadetime")) + && (subCommand != F("speed")) && (subCommand != F("fadedelay")) + && (subCommand != F("count")) && (subCommand != F("bgcolor")) + && (subCommand != F("on")) && (subCommand != F("off")) + && (subCommand != F("rgb")) && (subCommand != F("rainbow")) + && (subCommand != F("kitt")) && (subCommand != F("comet")) + && (subCommand != F("theatre")) && (subCommand != F("scan")) + && (subCommand != F("dualscan")) && (subCommand != F("twinkle")) + && (subCommand != F("sparkle")) && (subCommand != F("fire")) + && (subCommand != F("fireflicker")) && (subCommand != F("hsvone")) + && (subCommand != F("hsv")) && (subCommand != F("hsvline")) + && (subCommand != F("twinklefade")) && (subCommand != F("stop")) + && (subCommand != F("wipe")) && (subCommand != F("dualwipe")) + && (subCommand != F("colorfade")) && (subCommand != F("simpleclock")) + && (subCommand != F("faketv")) && (subCommand != F("statusrequest"))) { + log = F("NeoPixelBus: unknown subcommand: "); + log += subCommand; + addLog(LOG_LEVEL_INFO, log); + + String json; + printToWebJSON = true; + json += F("{\n"); + json += F("\"plugin\": \"128\",\n"); + json += F("\"log\": \""); + json += F("NeoPixelBus: unknown command: "); + json += subCommand; + json += F("\"\n"); + json += F("}\n"); + + // event->Source=EventValueSource::Enum::VALUE_SOURCE_HTTP; + SendStatus(event, json); // send http response to controller (JSON format) + printToWeb = false; + } + NeoPixelSendStatus(event); + } // command neopixel + + if (speed == 0) { mode = On; // speed = 0 = stop mode + } + speed = (speed > SPEED_MAX || speed < -SPEED_MAX) ? defaultspeed : speed; // avoid invalid values + fadetime = (fadetime <= 0) ? 20 : fadetime; + + break; + } + + case PLUGIN_FIFTY_PER_SECOND: + { + counter20ms++; + lastmode = mode; + + switch (mode) { + case Fade: + fade(); + break; + + case ColorFade: + colorfade(); + break; + + case Rainbow: + rainbow(); + break; + + case Kitt: + kitt(); + break; + + case Comet: + comet(); + break; + + case Theatre: + theatre(); + break; + + case Scan: + scan(); + break; + + case Dualscan: + dualscan(); + break; + + case Twinkle: + twinkle(); + break; + + case TwinkleFade: + twinklefade(); + break; + + case Sparkle: + sparkle(); + break; + + case Fire: + fire(); + break; + + case FireFlicker: + fire_flicker(); + break; + + case Wipe: + wipe(); + break; + + case Dualwipe: + dualwipe(); + break; + + case FakeTV: + faketv(); + break; + + case SimpleClock: + Plugin_128_simpleclock(); + break; + + default: + break; + } // switch mode + + Plugin_128_pixels->Show(); + + if (mode != lastmode) { + String log = ""; + log = F("NeoPixelBus: Mode Change: "); + log += modeName[mode]; + addLog(LOG_LEVEL_INFO, log); + NeoPixelSendStatus(event); + } + success = true; + break; + } + } + return success; +} + +void fade(void) { + for (int pixel = 0; pixel < pixelCount; pixel++) { + long zaehler = 20 * (counter20ms - starttime[pixel]); + float progress = (float)zaehler / (float)fadetime; + progress = (progress < 0) ? 0 : progress; + progress = (progress > 1) ? 1 : progress; + + # if defined(RGBW) || defined(GRBW) + RgbwColor updatedColor = RgbwColor::LinearBlend( + rgb_old[pixel], rgb_target[pixel], + progress); + # else // if defined(RGBW) || defined(GRBW) + RgbColor updatedColor = RgbColor::LinearBlend( + rgb_old[pixel], rgb_target[pixel], + progress); + # endif // if defined(RGBW) || defined(GRBW) + + if ((counter20ms > maxtime) && (Plugin_128_pixels->GetPixelColor(pixel).CalculateBrightness() == 0)) { + mode = Off; + } else if (counter20ms > maxtime) { + mode = On; + } + + Plugin_128_pixels->SetPixelColor(pixel, updatedColor); + } +} + +void colorfade(void) { + float progress = 0; + + difference = (endpixel - startpixel + pixelCount) % pixelCount; + + for (uint16_t i = 0; i <= difference; i++) + { + progress = (float)i / (difference - 1); + progress = (progress >= 1) ? 1 : progress; + progress = (progress <= 0) ? 0 : progress; + + # if defined(RGBW) || defined(GRBW) + RgbwColor updatedColor = RgbwColor::LinearBlend( + rgb, rrggbb, + progress); + # else // if defined(RGBW) || defined(GRBW) + RgbColor updatedColor = RgbColor::LinearBlend( + rgb, rrggbb, + progress); + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor((i + startpixel) % pixelCount, updatedColor); + } + mode = On; +} + +void wipe(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) { + if (speed > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step, rrggbb); + + if (_counter_mode_step > 0) { Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); } + } else { + Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step - 1, rrggbb); + + if (_counter_mode_step > 0) { Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step, rgb); } + } + + if (_counter_mode_step == pixelCount) { mode = On; } + _counter_mode_step++; + } +} + +void dualwipe(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) { + if (speed > 0) { + int i = _counter_mode_step - pixelCount; + i = abs(i); + Plugin_128_pixels->SetPixelColor(_counter_mode_step, rrggbb); + Plugin_128_pixels->SetPixelColor(i, rgb); + + if (_counter_mode_step > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); + Plugin_128_pixels->SetPixelColor(i - 1, rrggbb); + } + } else { + int i = (pixelCount / 2) - _counter_mode_step; + i = abs(i); + Plugin_128_pixels->SetPixelColor(_counter_mode_step + (pixelCount / 2), rrggbb); + Plugin_128_pixels->SetPixelColor(i, rgb); + + if (_counter_mode_step > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step + (pixelCount / 2) - 1, rgb); + Plugin_128_pixels->SetPixelColor(i - 1, rrggbb); + } + } + + if (_counter_mode_step >= pixelCount / 2) { + mode = On; + Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); + } + _counter_mode_step++; + } +} + +void faketv(void) { + if (counter20ms >= ftv_holdTime) { + difference = abs(endpixel - startpixel); + + if (ftv_elapsed >= ftv_fadeTime) { + // Read next 16-bit (5/6/5) color + ftv_hi = pgm_read_byte(&ftv_colors[pixelNum * 2]); + ftv_lo = pgm_read_byte(&ftv_colors[pixelNum * 2 + 1]); + + if (++pixelNum >= numPixels) { pixelNum = 0; } + + // Expand to 24-bit (8/8/8) + ftv_r8 = (ftv_hi & 0xF8) | (ftv_hi >> 5); + ftv_g8 = (ftv_hi << 5) | ((ftv_lo & 0xE0) >> 3) | ((ftv_hi & 0x06) >> 1); + ftv_b8 = (ftv_lo << 3) | ((ftv_lo & 0x1F) >> 2); + + // Apply gamma correction, further expand to 16/16/16 + ftv_nr = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_r8]) * 257; // New R/G/B + ftv_ng = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_g8]) * 257; + ftv_nb = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_b8]) * 257; + + ftv_totalTime = random(12, 125); // Semi-random pixel-to-pixel time + ftv_fadeTime = random(0, ftv_totalTime); // Pixel-to-pixel transition time + + if (random(10) < 3) { ftv_fadeTime = 0; // Force scene cut 30% of time + } + ftv_holdTime = counter20ms + ftv_totalTime - ftv_fadeTime; // Non-transition time + ftv_startTime = counter20ms; + } + + ftv_elapsed = counter20ms - ftv_startTime; + + if (ftv_fadeTime) { + ftv_r = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pr, ftv_nr); // 16-bit interp + ftv_g = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pg, ftv_ng); + ftv_b = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pb, ftv_nb); + } else { // Avoid divide-by-ftv_fraczero in map() + ftv_r = ftv_nr; + ftv_g = ftv_ng; + ftv_b = ftv_nb; + } + + for (ftv_i = 0; ftv_i < difference; ftv_i++) { + ftv_r8 = ftv_r >> 8; // Quantize to 8-bit + ftv_g8 = ftv_g >> 8; + ftv_b8 = ftv_b >> 8; + ftv_frac = (ftv_i << 16) / difference; // LED index scaled to 0-65535 (16Bit) + + if ((ftv_r8 < 255) && ((ftv_r & 0xFF) >= ftv_frac)) { ftv_r8++; // Boost some fraction + } + + if ((ftv_g8 < 255) && ((ftv_g & 0xFF) >= ftv_frac)) { ftv_g8++; // of LEDs to handle + } + + if ((ftv_b8 < 255) && ((ftv_b & 0xFF) >= ftv_frac)) { ftv_b8++; // interp > 8bit + } + Plugin_128_pixels->SetPixelColor(ftv_i + startpixel, RgbColor(ftv_r8, ftv_g8, ftv_b8)); + } + + ftv_pr = ftv_nr; // Prev RGB = new RGB + ftv_pg = ftv_ng; + ftv_pb = ftv_nb; + } +} + +/* + * Cycles a rainbow over the entire string of LEDs. + */ +void rainbow(void) { + long zaehler = 20 * (counter20ms - starttimerb); + float progress = (float)zaehler / (float)fadetime; + + if (fadeIn == true) { + Plugin_128_pixels->SetBrightness(progress * 255); + fadeIn = (progress == 1) ? false : true; + } + + for (int i = 0; i < pixelCount; i++) + { + uint8_t r1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255) >> 16); + uint8_t g1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255) >> 8); + uint8_t b1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255)); + Plugin_128_pixels->SetPixelColor(i, RgbColor(r1, g1, b1)); + } + mode = (rainbowspeed == 0) ? On : Rainbow; +} + +/* + * Put a value 0 to 255 in to get a color value. + * The colours are a transition r -> g -> b -> back to r + * Inspired by the Adafruit examples. + */ +uint32_t Wheel(uint8_t pos) { + pos = 255 - pos; + + if (pos < 85) { + return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); + } else if (pos < 170) { + pos -= 85; + return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3); + } else { + pos -= 170; + return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0); + } +} + +// Larson Scanner K.I.T.T. +void kitt(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) + { + for (uint16_t i = 0; i < pixelCount; i++) { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(i, px_rgb); + } + + uint16_t pos = 0; + + if (_counter_mode_step < pixelCount) { + pos = _counter_mode_step; + } else { + pos = (pixelCount * 2) - _counter_mode_step - 2; + } + + Plugin_128_pixels->SetPixelColor(pos, rgb); + + _counter_mode_step = (_counter_mode_step + 1) % ((pixelCount * 2) - 2); + } +} + +// Firing comets from one end. +void comet(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) + { + for (uint16_t i = 0; i < pixelCount; i++) { + if (speed > 0) { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(i, px_rgb); + } else { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(pixelCount - i - 1, px_rgb); + } + } + + if (speed > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step, rgb); + } else { + Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step - 1, rgb); + } + + _counter_mode_step = (_counter_mode_step + 1) % pixelCount; + } +} + +// Theatre lights +void theatre(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + if (speed > 0) { + Plugin_128_pixels->RotateLeft(1, 0, (pixelCount / count) * count - 1); + } else { + Plugin_128_pixels->RotateRight(1, 0, (pixelCount / count) * count - 1); + } + } +} + +/* + * Runs a single pixel back and forth. + */ +void scan(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + if (_counter_mode_step > uint16_t((pixelCount * 2) - 2)) { + _counter_mode_step = 0; + } + _counter_mode_step++; + + int i = _counter_mode_step - (pixelCount - 1); + i = abs(i); + + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + Plugin_128_pixels->SetPixelColor(abs(i), rgb); + } +} + +/* + * Runs two pixel back and forth in opposite directions. + */ +void dualscan(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) { + if (_counter_mode_step > uint16_t((pixelCount * 2) - 2)) { + _counter_mode_step = 0; + } + + _counter_mode_step++; + + int i = _counter_mode_step - (pixelCount - 1); + i = abs(i); + + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + Plugin_128_pixels->SetPixelColor(abs(i), rgb); + Plugin_128_pixels->SetPixelColor(pixelCount - (i + 1), rgb); + } +} + +/* + * Blink several LEDs on, reset, repeat. + * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ + */ +void twinkle(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + if (_counter_mode_step == 0) { + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + uint16_t min_leds = _max(1, pixelCount / 5); // make sure, at least one LED is on + uint16_t max_leds = _max(1, pixelCount / 2); // make sure, at least one LED is on + _counter_mode_step = random(min_leds, max_leds); + } + + Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); + + _counter_mode_step--; + } +} + +/* + * Blink several LEDs on, fading out. + */ +void twinklefade(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + for (uint16_t i = 0; i < pixelCount; i++) { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(i, px_rgb); + } + + if (random(count) < 50) { + Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); + } + } +} + +/* + * Blinks one LED at a time. + * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ + */ +void sparkle(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); + } +} + +// Fire +unsigned long fireTimer; +RgbColor leds[ARRAYSIZE]; + +void fire(void) { + if (counter20ms > fireTimer + 50 / fps) { + fireTimer = counter20ms; + Fire2012(); + RgbColor pixel; + + for (int i = 0; i < pixelCount; i++) { + pixel = leds[i]; + pixel = RgbColor::LinearBlend(pixel, RgbColor(0, 0, 0), (255 - brightness) / 255.0); + Plugin_128_pixels->SetPixelColor(i, pixel); + } + } +} + +/// random number seed +uint16_t rand16seed; // = RAND16_SEED; + +/// Generate an 8-bit random number +uint8_t random8() { + rand16seed = (rand16seed * ((uint16_t)(2053))) + ((uint16_t)(13849)); + + // return the sum of the high and low bytes, for better + // mixing and non-sequential correlation + return (uint8_t)(((uint8_t)(rand16seed & 0xFF)) + + ((uint8_t)(rand16seed >> 8))); +} + +/// Generate an 8-bit random number between 0 and lim +/// @param lim the upper bound for the result +uint8_t random8(uint8_t lim) { + uint8_t r = random8(); + + r = (r * lim) >> 8; + return r; +} + +/// Generate an 8-bit random number in the given range +/// @param min the lower bound for the random number +/// @param lim the upper bound for the random number +uint8_t random8(uint8_t min, uint8_t lim) { + uint8_t delta = lim - min; + uint8_t r = random8(delta) + min; + + return r; +} + +/// subtract one byte from another, saturating at 0x00 +/// @returns i - j with a floor of 0 +uint8_t qsub8(uint8_t i, uint8_t j) { + int t = i - j; + + if (t < 0) { t = 0; } + return t; +} + +/// add one byte to another, saturating at 0xFF +/// @param i - first byte to add +/// @param j - second byte to add +/// @returns the sum of i & j, capped at 0xFF +uint8_t qadd8(uint8_t i, uint8_t j) { + unsigned int t = i + j; + + if (t > 255) { t = 255; } + return t; +} + +/// The "video" version of scale8 guarantees that the output will +/// be only be zero if one or both of the inputs are zero. If both +/// inputs are non-zero, the output is guaranteed to be non-zero. +/// This makes for better 'video'/LED dimming, at the cost of +/// several additional cycles. +uint8_t scale8_video(uint8_t i, uint8_t scale) { + uint8_t j = (((int)i * (int)scale) >> 8) + ((i && scale) ? 1 : 0); + + // uint8_t nonzeroscale = (scale != 0) ? 1 : 0; + // uint8_t j = (i == 0) ? 0 : (((int)i * (int)(scale) ) >> 8) + nonzeroscale; + return j; +} + +void Fire2012(void) { + // Array of temperature readings at each simulation cell + static byte heat[ARRAYSIZE]; + + // Step 1. Cool down every cell a little + for (int i = 0; i < pixelCount; i++) { + heat[i] = qsub8(heat[i], random8(0, ((cooling * 10) / pixelCount) + 2)); + } + + // Step 2. Heat from each cell drifts 'up' and diffuses a little + for (int k = pixelCount - 1; k >= 2; k--) { + heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; + } + + // Step 3. Randomly ignite new 'sparks' of heat near the bottom + if (random8() < sparking) { + int y = random8(7); + heat[y] = qadd8(heat[y], random8(160, 255)); + } + + // Step 4. Map from heat cells to LED colors + for (int j = 0; j < pixelCount; j++) { + RgbColor heatcolor; + + // Scale 'heat' down from 0-255 to 0-191, + // which can then be easily divided into three + // equal 'thirds' of 64 units each. + uint8_t t192 = scale8_video(heat[j], 191); + + // calculate a value that ramps up from + // zero to 255 in each 'third' of the scale. + uint8_t heatramp = t192 & 0x3F; // 0..63 + heatramp <<= 2; // scale up to 0..252 + + // now figure out which third of the spectrum we're in: + if (t192 & 0x80) { + // we're in the hottest third + heatcolor.R = 255; // full red + heatcolor.G = 255; // full green + heatcolor.B = heatramp; // ramp up blue + } else if (t192 & 0x40) { + // we're in the middle third + heatcolor.R = 255; // full red + heatcolor.G = heatramp; // ramp up green + heatcolor.B = 0; // no blue + } else { + // we're in the coolest third + heatcolor.R = heatramp; // ramp up red + heatcolor.G = 0; // no green + heatcolor.B = 0; // no blue + } + + int pixelnumber; + + if (gReverseDirection) { + pixelnumber = (pixelCount - 1) - j; + } else { + pixelnumber = j; + } + leds[pixelnumber] = heatcolor; + } +} + +/* + * Fire flicker function + */ +void fire_flicker() { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + byte w = 0; // (SEGMENT.colors[0] >> 24) & 0xFF; + byte r = 255; // (SEGMENT.colors[0] >> 16) & 0xFF; + byte g = 96; // (SEGMENT.colors[0] >> 8) & 0xFF; + byte b = 12; // (SEGMENT.colors[0] & 0xFF); + byte lum = max(w, max(r, max(g, b))) / rev_intensity; + + for (uint16_t i = 0; i <= numPixels - 1; i++) { + int flicker = random8(lum); + + # if defined(RGBW) || defined(GRBW) + Plugin_128_pixels->SetPixelColor(i, RgbwColor(max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0))); + # else // if defined(RGBW) || defined(GRBW) + Plugin_128_pixels->SetPixelColor(i, RgbColor(max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0))); + # endif // if defined(RGBW) || defined(GRBW) + } + } +} + +void Plugin_128_simpleclock() { + byte Hours = node_time.hour() % 12; + byte Minutes = node_time.minute(); + byte Seconds = node_time.second(); + byte big_tick = 15; + byte small_tick = 5; + + // hack for sub-second calculations.... reset when first time new second begins.. + if (cooling != Seconds) { maxtime = counter20ms; } + cooling = Seconds; + Plugin_128_pixels->ClearTo(rrggbb); + + for (int i = 0; i < (60 / small_tick); i++) { + if (i % (big_tick / small_tick) == 0) { Plugin_128_pixels->SetPixelColor((i * pixelCount * small_tick / 60) % pixelCount, rgb_tick_b); } + else { Plugin_128_pixels->SetPixelColor((i * pixelCount * small_tick / 60) % pixelCount, rgb_tick_s); } + } + + + for (int i = 0; i < pixelCount; i++) { + if (round((((float)Seconds + ((float)counter20ms - (float)maxtime) / 50.0) * (float)pixelCount) / 60.0) == i) { + if (rgb_s_off == false) { + Plugin_128_pixels->SetPixelColor(i, rgb_s); + } + } + else if (round((((float)Minutes * 60.0) + (float)Seconds) / 60.0 * (float)pixelCount / 60.0) == i) { + Plugin_128_pixels->SetPixelColor(i, rgb_m); + } + else if (round(((float)Hours + (float)Minutes / 60) * (float)pixelCount / 12.0) == i) { + Plugin_128_pixels->SetPixelColor(i, rgb_h); + Plugin_128_pixels->SetPixelColor((i + 1) % pixelCount, rgb_h); + Plugin_128_pixels->SetPixelColor((i - 1 + pixelCount) % pixelCount, rgb_h); + } + } +} + +uint32_t rgbStr2Num(String rgbStr) { + uint32_t rgbDec = (int)strtoul(&rgbStr[0], NULL, 16); + + return rgbDec; +} + +void hex2rgb(String hexcolor) { + colorStr = hexcolor; + # if defined(RGBW) || defined(GRBW) + hexcolor.length() <= 6 + ? rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) + : rgb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # else // if defined(RGBW) || defined(GRBW) + rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # endif // if defined(RGBW) || defined(GRBW) +} + +void hex2rrggbb(String hexcolor) { + backgroundcolorStr = hexcolor; + # if defined(RGBW) || defined(GRBW) + hexcolor.length() <= 6 + ? rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) + : rrggbb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # else // if defined(RGBW) || defined(GRBW) + rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # endif // if defined(RGBW) || defined(GRBW) +} + +void hex2rgb_pixel(String hexcolor) { + colorStr = hexcolor; + + for (int i = 0; i < pixelCount; i++) { + # if defined(RGBW) || defined(GRBW) + hexcolor.length() <= 6 + ? rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) + : rgb_target[i] = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # else // if defined(RGBW) || defined(GRBW) + rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # endif // if defined(RGBW) || defined(GRBW) + } +} + +// --------------------------------------------------------------------------------- +// ------------------------------ JsonResponse ------------------------------------- +// --------------------------------------------------------------------------------- +void NeoPixelSendStatus(struct EventStruct *eventSource) { + String log = String(F("NeoPixelBusFX: Set ")) + rgb.R + + String(F("/")) + rgb.G + String(F("/")) + rgb.B; + + addLog(LOG_LEVEL_INFO, log); + + String json; + + printToWebJSON = true; + json += F("{\n"); + json += F("\"plugin\": \"128"); + json += F("\",\n\"mode\": \""); + json += modeName[mode]; + json += F("\",\n\"lastmode\": \""); + json += modeName[savemode]; + json += F("\",\n\"fadetime\": \""); + json += fadetime; + json += F("\",\n\"fadedelay\": \""); + json += fadedelay; + json += F("\",\n\"dim\": \""); + json += Plugin_128_pixels->GetBrightness(); + json += F("\",\n\"rgb\": \""); + json += colorStr; + json += F("\",\n\"hue\": \""); + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).H * 360), 0); + json += F("\",\n\"saturation\": \""); + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).S * 100), 0); + json += F("\",\n\"brightness\": \""); + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).B * 100), 0); + json += F("\",\n\"bgcolor\": \""); + json += backgroundcolorStr; + json += F("\",\n\"count\": \""); + json += count; + json += F("\",\n\"speed\": \""); + json += speed; + json += F("\",\n\"pixelcount\": \""); + json += pixelCount; + json += F("\"\n}\n"); + SendStatus(eventSource, json); // send http response to controller (JSON format) + printToWeb = false; +} + +#endif // USES_P128 diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index d5a142e36..488bec10e 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1455,7 +1455,7 @@ To create/register a plugin, you have to : #define USES_P127 // #endif #ifndef USES_P128 - #define USES_P128 // + #define USES_P128 // NeoPixelBusFX, (not yet working on 'plain' ESP32) #endif #ifndef USES_P129 #define USES_P129 // diff --git a/src/src/PluginStructs/P128_data_struct.cpp b/src/src/PluginStructs/P128_data_struct.cpp new file mode 100644 index 000000000..f84c2fa7b --- /dev/null +++ b/src/src/PluginStructs/P128_data_struct.cpp @@ -0,0 +1,8 @@ +#include "../../_Plugin_Helper.h" +#ifdef USES_P128 + +# include "../PluginStructs/P128_data_struct.h" + +// TODO: implementation code + +#endif // ifdef USES_P128 diff --git a/src/src/PluginStructs/P128_data_struct.h b/src/src/PluginStructs/P128_data_struct.h new file mode 100644 index 000000000..6ceba495d --- /dev/null +++ b/src/src/PluginStructs/P128_data_struct.h @@ -0,0 +1,2203 @@ +#ifndef PLUGINSTRUCTS_P128_DATA_STRUCT_H + +#define PLUGINSTRUCTS_P128_DATA_STRUCT_H +#include "../../_Plugin_Helper.h" +#ifdef USES_P128 + +// This is a copy of faketv.h, as provided by https://github.com/djcysmic/NeopixelBusFX + +const uint8_t PROGMEM ftv_gamma8[] = { + 0X01, 0X01, 0X01, 0X02, 0X02, 0X02, 0X03, 0X03, 0X03, 0X04, 0X04, 0X04, + 0X05, 0X05, 0X05, 0X06, 0X06, 0X06, 0X07, 0X07, 0X07, 0X08, 0X08, 0X08, + 0X09, 0X09, 0X0A, 0X0B, 0X0B, 0X0B, 0X0C, 0X0C, 0X0C, 0X0D, 0X0D, 0X0D, + 0X0E, 0X0E, 0X0E, 0X10, 0X10, 0X10, 0X11, 0X11, 0X11, 0X12, 0X12, 0X12, + 0X14, 0X14, 0X14, 0X15, 0X15, 0X15, 0X17, 0X17, 0X17, 0X18, 0X18, 0X19, + 0X1A, 0X1A, 0X1A, 0X1B, 0X1C, 0X1C, 0X1D, 0X1D, 0X1E, 0X1F, 0X1F, 0X1F, + 0X21, 0X21, 0X21, 0X22, 0X23, 0X23, 0X24, 0X25, 0X25, 0X26, 0X27, 0X27, + 0X28, 0X29, 0X29, 0X2A, 0X2B, 0X2B, 0X2C, 0X2D, 0X2D, 0X2F, 0X2F, 0X30, + 0X31, 0X31, 0X32, 0X33, 0X34, 0X34, 0X36, 0X36, 0X37, 0X38, 0X38, 0X39, + 0X3A, 0X3B, 0X3C, 0X3D, 0X3E, 0X3E, 0X40, 0X40, 0X41, 0X42, 0X43, 0X43, + 0X45, 0X46, 0X46, 0X48, 0X48, 0X49, 0X4B, 0X4B, 0X4C, 0X4E, 0X4E, 0X4F, + 0X50, 0X51, 0X52, 0X54, 0X54, 0X55, 0X57, 0X57, 0X58, 0X5A, 0X5B, 0X5B, + 0X5D, 0X5E, 0X5F, 0X60, 0X61, 0X62, 0X64, 0X65, 0X65, 0X67, 0X68, 0X69, + 0X6B, 0X6C, 0X6C, 0X6E, 0X6F, 0X70, 0X72, 0X73, 0X74, 0X75, 0X76, 0X77, + 0X79, 0X7A, 0X7B, 0X7D, 0X7E, 0X7F, 0X81, 0X82, 0X83, 0X85, 0X86, 0X87, + 0X89, 0X8A, 0X8B, 0X8D, 0X8E, 0X8F, 0X91, 0X92, 0X93, 0X95, 0X96, 0X98, + 0X99, 0X9B, 0X9C, 0X9E, 0X9F, 0XA0, 0XA2, 0XA3, 0XA5, 0XA6, 0XA8, 0XA9, + 0XAB, 0XAC, 0XAE, 0XAF, 0XB1, 0XB2, 0XB4, 0XB5, 0XB7, 0XB9, 0XBA, 0XBB, + 0XBD, 0XBF, 0XC0, 0XC2, 0XC3, 0XC5, 0XC7, 0XC8, 0XCA, 0XCC, 0XCD, 0XCF, + 0XD1, 0XD2, 0XD4, 0XD6, 0XD7, 0XD9, 0XDB, 0XDC, 0XDE, 0XE0, 0XE1, 0XE3, + 0XE5, 0XE6, 0XE8, 0XEA, 0XEC, 0XED, 0XEF, 0XF1, 0XF3, 0XF4, 0XF6, 0XF8, + 0XFA, 0XFB, 0XFD, 0XFF }, + ftv_colors[] = { + 0X8C, 0XD8, 0X8C, 0XF9, 0X8C, 0XD8, 0X84, 0X98, 0X7C, 0X77, 0X64, 0X16, + 0X43, 0X94, 0X4B, 0XB4, 0X43, 0X32, 0X42, 0XF1, 0X53, 0X51, 0X5B, 0X70, + 0X94, 0XF7, 0X8C, 0X94, 0X7C, 0X10, 0X84, 0X31, 0X8C, 0X72, 0X8C, 0X72, + 0X94, 0X92, 0X5A, 0XEC, 0X3A, 0X29, 0X42, 0X4A, 0X42, 0XCD, 0X5B, 0X91, + 0X74, 0X55, 0X74, 0X95, 0X7C, 0XD5, 0X7C, 0XD5, 0X74, 0X75, 0X6C, 0X34, + 0X6C, 0X34, 0X6C, 0X34, 0X7C, 0X53, 0X8C, 0X52, 0X7C, 0X33, 0X10, 0XC3, + 0X63, 0X50, 0X5B, 0X4F, 0X53, 0X2E, 0X42, 0X6A, 0X08, 0X84, 0X19, 0X8B, + 0X19, 0X8B, 0X21, 0X8B, 0X3A, 0X6E, 0X64, 0X12, 0X53, 0X91, 0X2A, 0X90, + 0X53, 0X70, 0X7C, 0X30, 0X74, 0X0F, 0X74, 0X30, 0X7B, 0XCD, 0X83, 0X49, + 0X83, 0X49, 0X83, 0XAC, 0X7C, 0X50, 0X64, 0X12, 0X63, 0XF2, 0X6C, 0X12, + 0X64, 0X12, 0X63, 0XD2, 0X7B, 0XCF, 0XCC, 0X86, 0X8C, 0X50, 0X94, 0X91, + 0X94, 0X92, 0X94, 0XB2, 0X8C, 0XF3, 0X74, 0X73, 0X83, 0XED, 0XAC, 0X2A, + 0X74, 0X31, 0X84, 0X50, 0X84, 0X91, 0X84, 0X71, 0X84, 0X70, 0X84, 0X70, + 0X84, 0X70, 0X7C, 0X30, 0X7C, 0X51, 0X84, 0X51, 0X94, 0X90, 0X9C, 0XF0, + 0X9C, 0XF0, 0X9C, 0XF0, 0X94, 0XF1, 0X94, 0XF1, 0X84, 0XB1, 0X84, 0XD1, + 0X84, 0XB2, 0X85, 0X13, 0X8C, 0XF2, 0X8D, 0X33, 0X95, 0X33, 0X95, 0X12, + 0X94, 0XF1, 0X8C, 0XF1, 0X94, 0XF1, 0XAC, 0XEE, 0X9D, 0X10, 0XA5, 0X2F, + 0X94, 0XAF, 0X94, 0XEF, 0X9C, 0XCE, 0X9C, 0X8E, 0X8C, 0X0C, 0X94, 0X4C, + 0X94, 0X2C, 0X94, 0X4C, 0X94, 0X2C, 0XA4, 0X0B, 0X93, 0XAA, 0X8B, 0XCA, + 0X7C, 0X52, 0X74, 0X35, 0X42, 0X8D, 0X83, 0XCB, 0X9C, 0X4C, 0X5A, 0XAB, + 0X42, 0X6C, 0X63, 0X8F, 0X63, 0X8F, 0X73, 0XF1, 0X6B, 0X6E, 0X4A, 0XCC, + 0X42, 0X8B, 0X52, 0XCC, 0X5A, 0XCC, 0X5A, 0XCC, 0X62, 0XCC, 0X5A, 0XCC, + 0X63, 0X6C, 0X6B, 0X8C, 0X6B, 0X8C, 0X6B, 0XCF, 0X74, 0X52, 0X6C, 0X11, + 0X74, 0X91, 0X63, 0XF0, 0X52, 0XEC, 0X52, 0XEC, 0X4A, 0XCC, 0X52, 0XEC, + 0X53, 0X0D, 0X5B, 0XCF, 0X5B, 0XCF, 0X5B, 0X8E, 0X5B, 0XAE, 0X63, 0XAE, + 0X63, 0XCD, 0X4B, 0X0C, 0X3A, 0X4C, 0X32, 0X0C, 0X3A, 0XAE, 0X32, 0X6D, + 0X3A, 0X8D, 0X3A, 0X6E, 0X29, 0XCB, 0X29, 0XCB, 0X31, 0XEC, 0X31, 0XEB, + 0X29, 0XEC, 0X3A, 0X8B, 0X42, 0XAC, 0X3A, 0XAC, 0X3A, 0XAC, 0X4A, 0XCC, + 0X42, 0XAA, 0X42, 0XAA, 0X4A, 0XAA, 0X4A, 0XAA, 0X3A, 0X6B, 0X32, 0X0D, + 0X32, 0X0D, 0X32, 0X0C, 0X52, 0XEC, 0X63, 0X2C, 0X5B, 0X2E, 0X63, 0X70, + 0X63, 0XB1, 0X63, 0XD3, 0X64, 0X14, 0X6C, 0X14, 0X74, 0X36, 0X6B, 0XF3, + 0X5B, 0X0B, 0X63, 0X6E, 0X84, 0X93, 0X7C, 0X52, 0X7C, 0X52, 0X84, 0X31, + 0X84, 0X53, 0X8C, 0X93, 0X62, 0XEE, 0X5A, 0XEE, 0X63, 0X6F, 0X5B, 0X0E, + 0X42, 0X4B, 0X53, 0X2E, 0X5B, 0X90, 0X6C, 0X12, 0X52, 0XCD, 0X42, 0X2B, + 0X63, 0X4F, 0X63, 0X6F, 0X63, 0X6F, 0X52, 0XAC, 0X6B, 0XD1, 0X7C, 0X94, + 0X7C, 0X73, 0X6B, 0XB0, 0X6B, 0X90, 0X73, 0XF1, 0X6B, 0XAF, 0X73, 0XF0, + 0X4A, 0XAC, 0X29, 0X88, 0X63, 0X0D, 0X6B, 0X6E, 0X6B, 0X4D, 0X6B, 0X2D, + 0X6B, 0X2D, 0X6B, 0X4E, 0X73, 0X6F, 0X83, 0XF1, 0X83, 0XD1, 0X83, 0XD1, + 0X83, 0XD1, 0X83, 0XD1, 0X83, 0XF1, 0X83, 0XF1, 0X83, 0XD1, 0X8C, 0X53, + 0X94, 0X73, 0X8C, 0X32, 0X8C, 0X32, 0X6B, 0X6E, 0X6B, 0X6D, 0X6B, 0X6D, + 0X6B, 0X6D, 0X6B, 0X6D, 0X6B, 0X6D, 0X6B, 0X6D, 0X6B, 0X6D, 0X6B, 0X6F, + 0X6B, 0X6F, 0X73, 0XB0, 0X73, 0XB0, 0X73, 0XB1, 0X6B, 0X4F, 0X73, 0XB0, + 0X7B, 0XF0, 0X7B, 0XF0, 0X7B, 0XF0, 0X7B, 0XD0, 0X83, 0XCF, 0X84, 0X11, + 0X8C, 0X93, 0X8C, 0X93, 0X8C, 0X93, 0X8C, 0X93, 0X95, 0X15, 0X94, 0XF4, + 0X84, 0X72, 0X84, 0X52, 0X84, 0X52, 0X7B, 0XAF, 0X73, 0X6D, 0X73, 0XAF, + 0X7C, 0X10, 0X94, 0XF5, 0X94, 0XF5, 0X94, 0XF5, 0X7B, 0XF0, 0X73, 0X6D, + 0X73, 0X6D, 0X7B, 0XAF, 0X73, 0XAE, 0X73, 0X6D, 0X73, 0XAF, 0X73, 0X8F, + 0X73, 0X6D, 0X73, 0X6D, 0X6B, 0X4C, 0X62, 0XEB, 0X62, 0XCA, 0X6A, 0XCA, + 0X62, 0X89, 0X84, 0X10, 0X94, 0XD3, 0X94, 0X92, 0X9C, 0XB2, 0X9C, 0XF4, + 0X9D, 0X15, 0X9C, 0XF4, 0XA5, 0X15, 0X5B, 0X2E, 0X32, 0X2B, 0X39, 0XE9, + 0X42, 0X2A, 0X5B, 0X90, 0X63, 0XB1, 0X53, 0X0E, 0X39, 0XC9, 0X4A, 0X8B, + 0X63, 0X6E, 0X63, 0X4E, 0X4A, 0X6B, 0X5A, 0XED, 0X4A, 0X8C, 0X3A, 0X0A, + 0X3A, 0X0A, 0X3A, 0X2B, 0X5B, 0X0D, 0X4A, 0XAD, 0X42, 0X4C, 0X42, 0X4B, + 0X42, 0X8C, 0X52, 0XAD, 0X52, 0XCD, 0X52, 0XED, 0X52, 0XEE, 0X4A, 0X8B, + 0X4A, 0X6B, 0X32, 0X09, 0X2A, 0X09, 0X29, 0XE9, 0X32, 0X2B, 0X08, 0XC5, + 0X5A, 0XEA, 0X94, 0XD1, 0X7B, 0X8C, 0X6A, 0XA9, 0X6A, 0X8B, 0X6A, 0X6B, + 0X62, 0XAB, 0X6A, 0XAB, 0X5A, 0X8A, 0X62, 0XAB, 0X73, 0X2B, 0X73, 0X0A, + 0X73, 0X6E, 0X7C, 0X13, 0X6B, 0X0D, 0X73, 0X0B, 0X7B, 0X2B, 0X84, 0X11, + 0X8C, 0X30, 0X83, 0XEF, 0X73, 0X8E, 0X73, 0XAE, 0X63, 0X4C, 0X5B, 0X0B, + 0X73, 0X8E, 0X7B, 0XCF, 0X7B, 0XCF, 0X7B, 0XEF, 0X7B, 0XAE, 0X7B, 0XEE, + 0X7C, 0X30, 0X7C, 0X0F, 0X8C, 0X0E, 0X94, 0X4F, 0X8C, 0X50, 0X8C, 0X70, + 0X8C, 0X50, 0X84, 0X4F, 0X8C, 0X70, 0X84, 0X91, 0X73, 0XAD, 0X84, 0X70, + 0X84, 0X0E, 0X83, 0XCD, 0X8B, 0XEE, 0X84, 0X2F, 0X7C, 0X4F, 0X6B, 0XEF, + 0X84, 0X2F, 0X94, 0X8F, 0X8B, 0XCA, 0X8B, 0XEB, 0X84, 0X0E, 0X84, 0X2F, + 0X83, 0XED, 0X7B, 0XEF, 0X7B, 0XEF, 0X83, 0XEF, 0X83, 0XEF, 0X84, 0X0F, + 0X84, 0X0F, 0X84, 0X10, 0X84, 0X10, 0X84, 0X30, 0X8C, 0X30, 0X84, 0X30, + 0X94, 0X4E, 0X9C, 0X2C, 0X84, 0XD4, 0X7C, 0X30, 0X73, 0XAE, 0X73, 0XF0, + 0X73, 0X8D, 0X7B, 0XEE, 0X7B, 0XCE, 0X7B, 0XEF, 0X8C, 0XF4, 0X8C, 0X70, + 0X73, 0XCE, 0X73, 0XF0, 0X84, 0X0F, 0X8B, 0XEE, 0X93, 0XCD, 0X93, 0XED, + 0X8C, 0XD4, 0X84, 0XB4, 0X7C, 0X52, 0X7C, 0X73, 0X73, 0XF1, 0X7C, 0X10, + 0X84, 0X73, 0X8C, 0XF4, 0X63, 0X4E, 0X29, 0X66, 0X39, 0XE8, 0X31, 0XA7, + 0X4A, 0X6B, 0X4A, 0X8B, 0X31, 0X88, 0X31, 0XA8, 0X31, 0XA9, 0X31, 0XCB, + 0X31, 0XCB, 0X52, 0X6C, 0X52, 0XAD, 0X6B, 0X0C, 0X4A, 0X6C, 0X3A, 0XB0, + 0X6B, 0X31, 0X62, 0X6D, 0X4B, 0X32, 0X53, 0X32, 0X4B, 0X33, 0X53, 0X32, + 0X73, 0X51, 0X63, 0X52, 0X4B, 0X54, 0X4B, 0X53, 0X4B, 0X54, 0X4B, 0X54, + 0X4B, 0X54, 0X4B, 0X54, 0X6B, 0X12, 0X9A, 0XD0, 0X83, 0XB3, 0X7B, 0X32, + 0X72, 0XB1, 0X8A, 0X8F, 0X62, 0XD0, 0X52, 0X90, 0X52, 0XB0, 0X52, 0XB0, + 0X32, 0X51, 0X08, 0X83, 0X00, 0X20, 0X21, 0X68, 0X3A, 0XF3, 0X3B, 0X33, + 0X33, 0X33, 0X3B, 0X53, 0X3B, 0X53, 0X3B, 0X33, 0X33, 0X13, 0X2A, 0XF3, + 0X33, 0X13, 0X32, 0XF3, 0X33, 0X13, 0X2A, 0XF3, 0X22, 0X93, 0X22, 0X73, + 0X1A, 0X53, 0X1A, 0X53, 0X22, 0X53, 0X39, 0XF0, 0X59, 0X29, 0X59, 0X29, + 0X59, 0X29, 0X59, 0X29, 0X59, 0X29, 0X59, 0X29, 0X59, 0X29, 0X61, 0X29, + 0X61, 0X29, 0X59, 0X08, 0X61, 0X09, 0X61, 0X8B, 0X51, 0X8A, 0X51, 0X69, + 0X49, 0X49, 0X59, 0X8B, 0X61, 0XCD, 0X59, 0X8C, 0X41, 0X2A, 0X38, 0XE8, + 0X30, 0XC8, 0X38, 0XC9, 0X40, 0XC9, 0X38, 0XC8, 0X48, 0XE9, 0X59, 0X4A, + 0X69, 0XAD, 0X82, 0X0E, 0X8A, 0X4F, 0X81, 0XED, 0X71, 0X6B, 0X39, 0X07, + 0X20, 0XE6, 0X29, 0X06, 0X29, 0X27, 0X20, 0XA5, 0X28, 0XC6, 0X31, 0X08, + 0X39, 0X08, 0X39, 0X07, 0X28, 0XC5, 0X30, 0XA6, 0X30, 0XA6, 0X30, 0XA6, + 0X38, 0XC6, 0X61, 0XEB, 0X82, 0X8E, 0X72, 0X2C, 0X72, 0X2B, 0X62, 0X2A, + 0X51, 0XC9, 0X49, 0X8A, 0X41, 0X68, 0X59, 0XA9, 0X79, 0XEA, 0X81, 0XE9, + 0X81, 0XE9, 0X89, 0XC7, 0X89, 0XE7, 0X89, 0XE7, 0X81, 0XC7, 0X81, 0XC7, + 0X81, 0XC7, 0X71, 0X86, 0X69, 0X66, 0X89, 0X47, 0X89, 0X67, 0X81, 0X47, + 0X70, 0XE6, 0X58, 0XE6, 0X40, 0XE6, 0X38, 0XC7, 0X50, 0XC8, 0X68, 0XC9, + 0X68, 0XC9, 0X68, 0X88, 0X68, 0XA7, 0X68, 0XE7, 0X60, 0XC7, 0X60, 0XC7, + 0X58, 0XC7, 0X50, 0XC7, 0X50, 0XA7, 0X50, 0XC7, 0X58, 0XC8, 0X60, 0XC9, + 0X60, 0XA9, 0X30, 0X44, 0X00, 0X00, 0X08, 0X01, 0X20, 0X85, 0X42, 0XB3, + 0X42, 0XD5, 0X5A, 0X8F, 0X92, 0X2D, 0X7A, 0X4B, 0X79, 0X88, 0X82, 0X08, + 0X82, 0X27, 0X81, 0XC8, 0X8A, 0X4D, 0X7A, 0XAC, 0X82, 0XEE, 0X84, 0X12, + 0X83, 0X50, 0X79, 0XCB, 0X81, 0XEA, 0X89, 0XC8, 0X91, 0XC8, 0X89, 0XE9, + 0X7A, 0X4D, 0X82, 0X4C, 0X92, 0X29, 0X92, 0X29, 0X99, 0XEB, 0XA1, 0XCB, + 0XA1, 0X8B, 0X91, 0XCD, 0X91, 0XCC, 0X9A, 0X49, 0X9A, 0X0D, 0X9A, 0X0C, + 0X9A, 0X49, 0X9A, 0X4A, 0X9A, 0X6A, 0X9A, 0X2A, 0XAA, 0X2A, 0XB2, 0X2B, + 0X8A, 0X4D, 0X62, 0X4A, 0X62, 0X4B, 0X41, 0X46, 0X28, 0XE3, 0X10, 0XA2, + 0X39, 0X44, 0X31, 0X45, 0X18, 0XC2, 0X18, 0XC2, 0X18, 0XC2, 0X18, 0XC3, + 0X10, 0XC3, 0X18, 0XC4, 0X29, 0X09, 0X10, 0XA8, 0X18, 0XC7, 0X31, 0X06, + 0X41, 0X67, 0X20, 0XE4, 0X10, 0XA3, 0X28, 0XE5, 0X18, 0XE5, 0X21, 0X06, + 0X31, 0X47, 0X20, 0XE4, 0X20, 0XC5, 0X31, 0X47, 0X18, 0XC6, 0X10, 0XA5, + 0X5A, 0X4B, 0X83, 0XB1, 0X73, 0X70, 0X7B, 0X0D, 0X72, 0X8B, 0X7A, 0XAB, + 0X83, 0X0C, 0X8A, 0XEC, 0X82, 0XCB, 0X82, 0XCC, 0X82, 0X69, 0X82, 0X49, + 0X8A, 0X6A, 0X82, 0X6A, 0X82, 0X8B, 0X6A, 0XCE, 0X83, 0X4E, 0X8B, 0X8F, + 0X7B, 0X2D, 0X73, 0X0C, 0X73, 0X0C, 0X83, 0X2C, 0X93, 0X4D, 0X82, 0XEB, + 0X7A, 0XEA, 0X8B, 0X0B, 0X6A, 0XCB, 0X7A, 0XCB, 0X83, 0X0B, 0X92, 0X69, + 0X9A, 0X27, 0X82, 0XAA, 0X82, 0XAA, 0X7A, 0XCC, 0X7B, 0X0D, 0X6A, 0X2A, + 0X72, 0X09, 0X82, 0X8C, 0X83, 0X0D, 0X7B, 0X0E, 0X7B, 0X0E, 0X7A, 0XEC, + 0X72, 0XCC, 0X6A, 0XCC, 0X72, 0XCD, 0X6A, 0XCD, 0X6A, 0XAB, 0X6A, 0X8B, + 0X62, 0X8B, 0X62, 0X8B, 0X6A, 0X8A, 0X6A, 0X8A, 0X6A, 0X8A, 0X62, 0X6A, + 0X5A, 0X6A, 0X5A, 0X4A, 0X62, 0X4A, 0X5A, 0X4A, 0X5A, 0X49, 0X5A, 0X6A, + 0X62, 0X8A, 0X62, 0X8A, 0X62, 0X69, 0X62, 0X6A, 0X62, 0X6A, 0X62, 0X69, + 0X62, 0X48, 0X62, 0X28, 0X6A, 0X69, 0X6A, 0XAB, 0X62, 0X6B, 0X5A, 0X4A, + 0X62, 0X4B, 0X62, 0X69, 0X62, 0X6A, 0X62, 0X4A, 0X6A, 0X6A, 0X72, 0X6A, + 0X6A, 0X89, 0X62, 0X49, 0X5A, 0X48, 0X5A, 0X29, 0X52, 0X08, 0X5A, 0X49, + 0X62, 0X8B, 0X5A, 0X6B, 0X5A, 0X8B, 0X62, 0X6A, 0X62, 0X6A, 0X5A, 0X2A, + 0X5A, 0X2A, 0X5A, 0X4A, 0X5A, 0X6A, 0X52, 0X29, 0X5A, 0X29, 0X62, 0X4A, + 0X62, 0X6B, 0X62, 0XAC, 0X6A, 0XAC, 0X6A, 0XCC, 0X6A, 0X6A, 0X62, 0X6A, + 0X6A, 0X8B, 0X72, 0X8A, 0X7A, 0XAA, 0X72, 0XAA, 0X7A, 0XCB, 0X72, 0XA8, + 0X72, 0X67, 0X72, 0X67, 0X72, 0X89, 0X7A, 0XAA, 0X7A, 0XA9, 0X72, 0XA9, + 0X72, 0XCA, 0X72, 0XAA, 0X7A, 0XA9, 0X8B, 0X2A, 0X6A, 0XAA, 0X5A, 0X2A, + 0X62, 0X6A, 0X7A, 0XC9, 0X72, 0XC9, 0X82, 0XEA, 0X82, 0XC9, 0X82, 0XA9, + 0X82, 0XA9, 0X72, 0XAB, 0X72, 0XAB, 0X7A, 0XAB, 0X72, 0XAB, 0X6A, 0XAA, + 0X9A, 0XED, 0XA3, 0X2E, 0X69, 0XE8, 0X49, 0X65, 0X51, 0XC7, 0X6A, 0X8A, + 0X6A, 0X8A, 0X6A, 0X8A, 0X6A, 0X8A, 0X6A, 0X8A, 0X6A, 0X8A, 0X6A, 0XAA, + 0X6A, 0X8B, 0X72, 0X8A, 0X72, 0X6B, 0X72, 0XAA, 0X72, 0XAB, 0X6A, 0X8B, + 0X6A, 0XAB, 0X72, 0XAC, 0X72, 0XAC, 0X72, 0XCC, 0X6A, 0XAA, 0X6A, 0X47, + 0X62, 0X27, 0X62, 0X28, 0X6A, 0X68, 0X6A, 0X6A, 0X6A, 0X6C, 0X6A, 0XAD, + 0X72, 0X8C, 0X72, 0XAE, 0X62, 0X4C, 0X6A, 0XAC, 0X72, 0XEE, 0X62, 0X6B, + 0X62, 0X2A, 0X79, 0XAA, 0X71, 0X8C, 0X29, 0XAF, 0X11, 0X6E, 0X4A, 0X6A, + 0X6A, 0XA8, 0X51, 0XC8, 0X51, 0X26, 0X31, 0X25, 0X19, 0X25, 0X19, 0X26, + 0X21, 0X66, 0X10, 0X63, 0X18, 0X84, 0X20, 0X80, 0X28, 0XE0, 0X31, 0XA1, + 0X29, 0X81, 0X48, 0X81, 0X58, 0X00, 0X58, 0X00, 0X60, 0X00, 0X58, 0X00, + 0X50, 0XA3, 0X58, 0XC3, 0X68, 0X00, 0X68, 0X00, 0X70, 0XE3, 0X69, 0X86, + 0X68, 0XA3, 0X61, 0XA7, 0X48, 0X82, 0X50, 0X81, 0X51, 0X05, 0X62, 0X28, + 0X49, 0XA8, 0X39, 0X86, 0X51, 0XC8, 0X82, 0X2C, 0X82, 0X0A, 0X69, 0XC9, + 0X61, 0XA9, 0X59, 0XE7, 0X62, 0X29, 0X62, 0X49, 0X49, 0XA7, 0X51, 0XC8, + 0X51, 0XC7, 0X49, 0XA6, 0X5A, 0X8A, 0X5A, 0X6A, 0X4A, 0X2C, 0X42, 0X4F, + 0X42, 0X70, 0X4A, 0X91, 0X5A, 0XB0, 0X5A, 0X8F, 0X52, 0X50, 0X5A, 0XAF, + 0X62, 0XCF, 0X49, 0XEF, 0X41, 0XCE, 0X49, 0XEF, 0X52, 0X0F, 0X52, 0X10, + 0X52, 0X2F, 0X52, 0X6D, 0X5A, 0X6D, 0X5A, 0X2D, 0X4A, 0X0C, 0X52, 0X2C, + 0X49, 0XCF, 0X49, 0XB0, 0X49, 0XAF, 0X3A, 0X4D, 0X32, 0XAC, 0X32, 0X8D, + 0X32, 0XAD, 0X3A, 0XCC, 0X32, 0X2A, 0X2A, 0X2A, 0X32, 0X4C, 0X42, 0X2E, + 0X52, 0X50, 0X62, 0XF0, 0X62, 0XCF, 0X4A, 0X4E, 0X4A, 0X2F, 0X4A, 0X2F, + 0X4A, 0X2F, 0X41, 0XEF, 0X39, 0XCF, 0X5A, 0X8F, 0X52, 0X8F, 0X7A, 0X64, + 0X92, 0XA0, 0X8A, 0X81, 0X8A, 0X80, 0X92, 0X80, 0X8A, 0X80, 0X9A, 0XC1, + 0XAB, 0X04, 0X41, 0XCE, 0X4A, 0X2C, 0X52, 0X29, 0X4A, 0X0A, 0X4A, 0X2C, + 0X41, 0XC9, 0X41, 0XE2, 0X4A, 0X02, 0X4A, 0X22, 0X29, 0X22, 0X18, 0XC1, + 0X31, 0X82, 0X39, 0XC2, 0X42, 0X02, 0X41, 0XE2, 0X42, 0X02, 0X41, 0XE2, + 0X42, 0X02, 0X31, 0X62, 0X21, 0X02, 0X18, 0XC1, 0X21, 0X02, 0X39, 0XA4, + 0X31, 0X87, 0X31, 0XCC, 0X29, 0X87, 0X18, 0XE2, 0X18, 0XC2, 0X18, 0XE2, + 0X18, 0XC2, 0X08, 0X61, 0X31, 0X47, 0X41, 0XCA, 0X21, 0X04, 0X10, 0X81, + 0X18, 0XE2, 0X18, 0XC1, 0X28, 0XE7, 0X39, 0X6E, 0X39, 0X69, 0X39, 0X8A, + 0X31, 0X4C, 0X5A, 0X6B, 0X52, 0X0B, 0X41, 0X6B, 0X49, 0XCC, 0X52, 0X2E, + 0X52, 0X0E, 0X4A, 0X0D, 0X4A, 0X0D, 0X52, 0X2D, 0X72, 0XEC, 0X6A, 0X28, + 0X83, 0X67, 0X6B, 0XE4, 0X4B, 0X6C, 0X43, 0X4E, 0X43, 0X4D, 0X43, 0X4D, + 0X4B, 0X4E, 0X6A, 0XAF, 0X6A, 0XAE, 0X6A, 0XB0, 0X6A, 0XF0, 0X79, 0XEC, + 0X79, 0X0A, 0X79, 0X0A, 0X89, 0XEB, 0X5B, 0XCF, 0X63, 0X86, 0X63, 0X24, + 0X63, 0X65, 0X82, 0X22, 0X6A, 0XAB, 0X43, 0XF2, 0X43, 0XB1, 0X4B, 0XD2, + 0X4B, 0XD2, 0X4B, 0XD2, 0X4B, 0XF0, 0X5A, 0X4A, 0X80, 0XE7, 0XA2, 0X45, + 0X93, 0X07, 0X8A, 0XEA, 0X41, 0X6E, 0X39, 0X8E, 0X8C, 0X71, 0X8C, 0X30, + 0X7B, 0X6C, 0X8B, 0XCD, 0X83, 0X8D, 0X9B, 0XEE, 0X94, 0X2F, 0X83, 0X4D, + 0X5C, 0XFA, 0X65, 0X1A, 0X64, 0XFA, 0X85, 0X12, 0X84, 0X8D, 0X7C, 0X4D, + 0X84, 0X2C, 0X8C, 0X8F, 0X8C, 0XF0, 0X8C, 0XD0, 0X94, 0X8F, 0X93, 0XAC, + 0X93, 0XAC, 0X94, 0X4E, 0X8C, 0XD0, 0X8C, 0XAF, 0X8C, 0XD0, 0X8C, 0XF0, + 0X8C, 0XF2, 0X84, 0XF7, 0X7C, 0XB4, 0X7C, 0X92, 0X7C, 0X92, 0X7C, 0X92, + 0X8B, 0XF1, 0X93, 0XB0, 0X93, 0XB0, 0X9C, 0X11, 0XA4, 0X52, 0XAC, 0X71, + 0XA4, 0X73, 0XA4, 0X32, 0X8C, 0X94, 0X8C, 0XB4, 0X8C, 0X94, 0X8C, 0X94, + 0X8C, 0X93, 0X8C, 0X93, 0X7C, 0X95, 0X7C, 0XB6, 0X74, 0XB7, 0X84, 0X51, + 0X84, 0X30, 0X8C, 0X10, 0X94, 0X50, 0X8C, 0X50, 0X8C, 0XCC, 0X84, 0XCA, + 0X7C, 0XCE, 0X74, 0XF9, 0X74, 0XD9, 0X6C, 0XB7, 0X74, 0XF7, 0X75, 0X7B, + 0X94, 0X30, 0X7C, 0XD2, 0X7C, 0XCD, 0X74, 0XD7, 0X6C, 0XD7, 0X74, 0XD2, + 0X7D, 0X56, 0X7D, 0X35, 0X84, 0XEA, 0X64, 0X94, 0X64, 0X96, 0X6C, 0XB6, + 0X6C, 0XD6, 0X6C, 0XB6, 0X6D, 0X39, 0X6C, 0XD7, 0X84, 0X93, 0XAC, 0X8D, + 0XAC, 0X6C, 0XB4, 0XAD, 0XB4, 0XEE, 0XAC, 0XEF, 0XAC, 0XAF, 0XA4, 0X2E, + 0XB4, 0X4B, 0XBC, 0XAA, 0XCD, 0X4B, 0XCD, 0X4B, 0XBD, 0X2D, 0XB5, 0X0E, + 0XD3, 0XE9, 0XB4, 0X6A, 0XA5, 0X4D, 0XBD, 0X0D, 0XBC, 0XCC, 0XBC, 0XCD, + 0XB4, 0X8B, 0X9D, 0X4F, 0X8D, 0X0F, 0X95, 0X0F, 0X8D, 0X2F, 0XA5, 0X4B, + 0XC5, 0X46, 0XBD, 0X07, 0XBC, 0XE7, 0XBD, 0X07, 0XAC, 0XE8, 0XBC, 0X2C, + 0XAB, 0XED, 0XAC, 0XCF, 0X9D, 0X72, 0X9D, 0X31, 0X9C, 0XAF, 0X94, 0XD0, + 0X75, 0X14, 0X7C, 0X90, 0XA3, 0XE6, 0XB4, 0X65, 0XC4, 0X83, 0XC4, 0XA4, + 0XA3, 0XA8, 0X52, 0X8E, 0X10, 0X63, 0X00, 0X00, 0X00, 0X00, 0X08, 0X85, + 0X29, 0X4A, 0X29, 0X4A, 0X29, 0X6A, 0X29, 0X4A, 0X31, 0X2A, 0X41, 0X2A, + 0X41, 0X4A, 0X39, 0X09, 0X08, 0X22, 0X00, 0X00, 0X00, 0X00, 0X00, 0X20, + 0X08, 0X62, 0X08, 0X62, 0X08, 0X62, 0X08, 0X62, 0X08, 0X82, 0X10, 0XA3, + 0X10, 0XA4, 0X10, 0XC4, 0X10, 0XE5, 0X19, 0X47, 0X11, 0X27, 0X19, 0X68, + 0X2A, 0X0A, 0X3A, 0XCD, 0X53, 0X90, 0X6C, 0X52, 0X74, 0X93, 0X84, 0XF3, + 0X8D, 0X12, 0X7C, 0XB0, 0X7C, 0X4F, 0X7C, 0X6F, 0X74, 0X6E, 0X63, 0XED, + 0X6B, 0XAD, 0X6B, 0X8D, 0X6B, 0X8E, 0X73, 0XCF, 0X7C, 0X30, 0X7C, 0X72, + 0X6C, 0X33, 0X5B, 0XD3, 0X4B, 0XD5, 0X4C, 0X18, 0X3B, 0XD7, 0X33, 0X76, + 0X2B, 0X15, 0X2A, 0XD3, 0X2A, 0XD3, 0X3A, 0XF4, 0X3A, 0XF4, 0X2A, 0X73, + 0X22, 0X12, 0X1A, 0X13, 0X19, 0XF5, 0X19, 0XF6, 0X19, 0XD5, 0X19, 0XB3, + 0X19, 0X71, 0X19, 0X91, 0X19, 0X2F, 0X00, 0X23, 0X00, 0X21, 0X09, 0X08, + 0X09, 0X48, 0X11, 0X67, 0X09, 0X48, 0X08, 0XEA, 0X08, 0XAD, 0X19, 0X10, + 0X29, 0XF2, 0X29, 0XF2, 0X21, 0XD1, 0X21, 0XD1, 0X21, 0XB1, 0X21, 0XD1, + 0X31, 0XD1, 0X49, 0X8F, 0X69, 0X8E, 0X81, 0XAD, 0X91, 0XED, 0X9A, 0X0D, + 0X91, 0XEC, 0X89, 0XCC, 0X8A, 0X0C, 0X99, 0XCE, 0XB1, 0XF4, 0XBA, 0X77, + 0XA2, 0X35, 0X81, 0XF2, 0X69, 0XD0, 0X51, 0XAE, 0X41, 0X8E, 0X29, 0X6C, + 0X19, 0X4B, 0X11, 0X6B, 0X11, 0X4B, 0X11, 0X2B, 0X09, 0X0B, 0X08, 0XC9, + 0X08, 0X89, 0X00, 0X24, 0X00, 0X01, 0X00, 0X01, 0X00, 0X01, 0X00, 0X01, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X10, 0X20, + 0X69, 0X24, 0X79, 0X45, 0X79, 0X44, 0X81, 0X63, 0X81, 0X83, 0X81, 0XA3, + 0X81, 0X83, 0X89, 0XA5, 0X92, 0X07, 0X69, 0X65, 0X08, 0X20, 0X00, 0X00, + 0X4A, 0X27, 0X62, 0XEA, 0X62, 0XEA, 0X6B, 0X0B, 0X6A, 0XEA, 0X73, 0X4C, + 0X73, 0X2C, 0X73, 0X2B, 0X6A, 0XCA, 0X52, 0X27, 0X52, 0X48, 0X6B, 0X4B, + 0X73, 0XCC, 0X6B, 0X4A, 0X6B, 0X49, 0X6B, 0X0A, 0X62, 0XEC, 0X62, 0XEC, + 0X62, 0XEC, 0X62, 0XEC, 0X5A, 0XCC, 0X5A, 0XAB, 0X5A, 0XCB, 0X5A, 0XCC, + 0X62, 0X8C, 0X62, 0XAC, 0X5A, 0XAB, 0X5A, 0X49, 0X73, 0X0C, 0X9C, 0X30, + 0X7B, 0X6D, 0X5A, 0X69, 0X5A, 0X6A, 0X7B, 0X4D, 0XA4, 0X6F, 0X8C, 0X30, + 0X7B, 0XEC, 0X6B, 0X29, 0X5A, 0X89, 0X62, 0XA9, 0X52, 0X68, 0X6B, 0X0A, + 0X94, 0X0F, 0X8B, 0XEE, 0X93, 0XEE, 0X94, 0X2F, 0X7B, 0X0A, 0X7B, 0XCC, + 0X83, 0XCA, 0X73, 0X0B, 0X73, 0X0B, 0X62, 0XEB, 0X5A, 0XA9, 0X94, 0X0F, + 0X94, 0X2F, 0X8B, 0XCE, 0X8B, 0XAD, 0X8C, 0X10, 0X8C, 0X72, 0X8C, 0X72, + 0X8C, 0X72, 0X8C, 0X93, 0X8C, 0X6F, 0X8C, 0X8F, 0X84, 0X50, 0X84, 0X4F, + 0X84, 0X4E, 0X7B, 0XEB, 0X7B, 0X8C, 0X62, 0XAA, 0X6A, 0XA9, 0X7B, 0X6C, + 0X83, 0X6B, 0X93, 0XAA, 0X7B, 0X2A, 0X5A, 0X68, 0X73, 0X4C, 0X8C, 0XB3, + 0X84, 0X0F, 0X84, 0X0F, 0X83, 0XCF, 0X7B, 0X4A, 0X7B, 0X6A, 0X73, 0X8A, + 0X73, 0XCD, 0X7B, 0XEE, 0X7B, 0XCC, 0X9C, 0X4E, 0X9B, 0XCB, 0X83, 0XAC, + 0X83, 0XAC, 0X93, 0X08, 0X93, 0X09, 0X93, 0X29, 0X93, 0X09, 0X72, 0XEA, + 0X6A, 0XEB, 0X6A, 0XEB, 0X73, 0X0B, 0X83, 0X09, 0X72, 0XAC, 0X7A, 0XCD, + 0X7A, 0XCC, 0X6A, 0X6D, 0X72, 0X8D, 0X72, 0X8C, 0X7A, 0XEE, 0X52, 0X29, + 0X31, 0X86, 0X31, 0X86, 0X29, 0X65, 0X31, 0X86, 0X39, 0XA7, 0X39, 0XA7, + 0X41, 0XE7, 0X4A, 0X07, 0X4A, 0X07, 0X41, 0XE7, 0X4A, 0X08, 0X41, 0XE7, + 0X41, 0XE8, 0X4A, 0X08, 0X41, 0XE7, 0X41, 0XE7, 0X31, 0XA7, 0X62, 0X49, + 0X5A, 0X49, 0X52, 0X6A, 0X8B, 0XAD, 0X83, 0XAC, 0X8B, 0XED, 0X94, 0X0E, + 0X9B, 0XCE, 0X94, 0X0E, 0X94, 0X0E, 0X9C, 0X2F, 0X94, 0X0F, 0X82, 0XE9, + 0X7A, 0X88, 0X83, 0X2B, 0X84, 0X30, 0X94, 0X0F, 0X94, 0X2F, 0X8C, 0X0F, + 0X94, 0X50, 0X8C, 0X10, 0X8B, 0XB0, 0X93, 0XD0, 0X93, 0XB1, 0X93, 0XF0, + 0X94, 0X0F, 0X8B, 0XEF, 0X83, 0X8D, 0X83, 0X8C, 0X83, 0X8C, 0X83, 0X8C, + 0X6B, 0X4C, 0X6B, 0X6D, 0X6B, 0X6D, 0X63, 0X4E, 0X6B, 0X4D, 0X63, 0X0C, + 0X73, 0X6D, 0X62, 0X8A, 0X4A, 0X28, 0X52, 0X48, 0X52, 0X28, 0X5A, 0X69, + 0X83, 0XAF, 0X6A, 0XAA, 0X7B, 0X6D, 0X83, 0XCE, 0X83, 0XAE, 0X7B, 0XAF, + 0X83, 0XEE, 0X83, 0XEF, 0X83, 0XEE, 0X8B, 0XEE, 0X8C, 0X51, 0X8C, 0X0F, + 0X8B, 0X4C, 0X6B, 0X4C, 0X6B, 0X4D, 0X63, 0X0B, 0X5A, 0XA7, 0X73, 0X2D, + 0X93, 0XF2, 0X73, 0X4E, 0X4A, 0X09, 0X83, 0X71, 0X83, 0X8F, 0X7B, 0X8F, + 0X7B, 0X8F, 0X7B, 0X8F, 0X7B, 0XAE, 0X62, 0XCB, 0X62, 0X6A, 0X83, 0X8D, + 0X8C, 0X30, 0X83, 0XEE, 0X83, 0XCE, 0X8C, 0X0F, 0X83, 0XCE, 0X84, 0X2F, + 0X73, 0X6D, 0X72, 0XCA, 0X72, 0XCB, 0X6A, 0XEB, 0X6B, 0X4B, 0X6B, 0X6C, + 0X63, 0X2B, 0X52, 0XAA, 0X52, 0X89, 0X42, 0X28, 0X3A, 0X07, 0X3A, 0X07, + 0X4A, 0X68, 0X52, 0XA9, 0X52, 0X89, 0X42, 0X27, 0X39, 0XE6, 0X39, 0XC6, + 0X42, 0X07, 0X4A, 0X48, 0X31, 0XC7, 0X29, 0XC8, 0X32, 0X2B, 0X32, 0X2B, + 0X2A, 0X0A, 0X32, 0X0A, 0X3A, 0X4A, 0X3A, 0X4B, 0X3A, 0X4B, 0X3A, 0X2A, + 0X3A, 0X2A, 0X3A, 0X4A, 0X32, 0X4A, 0X32, 0X4A, 0X32, 0X6B, 0X3A, 0X8B, + 0X32, 0X4B, 0X21, 0XA8, 0X00, 0X63, 0X00, 0X84, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X39, 0X86, 0X5A, 0X69, 0X5A, 0X6A, 0X5A, 0X8C, 0X52, 0X8C, + 0X52, 0X8D, 0X52, 0XAD, 0X52, 0X8C, 0X52, 0XAD, 0X32, 0X0A, 0X29, 0XE9, + 0X10, 0XC4, 0X00, 0X00, 0X20, 0X63, 0X81, 0XEF, 0X81, 0XEF, 0X81, 0XEE, + 0X81, 0XCE, 0X69, 0X6B, 0X59, 0X4A, 0X61, 0X6B, 0X69, 0X8B, 0X71, 0X8B, + 0X71, 0XAB, 0X69, 0XAB, 0X61, 0XAB, 0X69, 0X6B, 0X71, 0X6C, 0X79, 0X8D, + 0X79, 0X8D, 0X71, 0X6D, 0X71, 0X6C, 0X71, 0X6C, 0X71, 0X6C, 0X71, 0X6C, + 0X71, 0X6C, 0X71, 0X6C, 0X71, 0X6C, 0X71, 0X4C, 0X71, 0X8D, 0X51, 0X6D, + 0X41, 0XCE, 0X41, 0XAE, 0X41, 0XAE, 0X41, 0XAD, 0X41, 0XAD, 0X41, 0XAD, + 0X41, 0X8D, 0X39, 0X6D, 0X39, 0X6C, 0X39, 0X6C, 0X39, 0X6C, 0X39, 0X6C, + 0X39, 0X6C, 0X39, 0X4C, 0X39, 0X4C, 0X39, 0X4C, 0X49, 0XAC, 0X6A, 0XEF, + 0X73, 0X2F, 0X4A, 0X8E, 0X22, 0X0B, 0X22, 0X0B, 0X22, 0X0B, 0X22, 0X0B, + 0X2A, 0X4D, 0X32, 0X6E, 0X32, 0X6E, 0X2A, 0X4E, 0X2A, 0X4E, 0X2A, 0X6E, + 0X2A, 0X4E, 0X32, 0X6F, 0X3A, 0X2D, 0X32, 0X0C, 0X32, 0X0C, 0X32, 0X0C, + 0X32, 0X0C, 0X32, 0X0C, 0X31, 0XEC, 0X31, 0XEC, 0X32, 0X0C, 0X42, 0X8E, + 0X3A, 0X8E, 0X3A, 0X6E, 0X3A, 0X6E, 0X3A, 0X6D, 0X42, 0X8E, 0X4A, 0X8E, + 0X4A, 0XAF, 0X42, 0X6E, 0X29, 0X8B, 0X21, 0X4B, 0X29, 0X6C, 0X29, 0X6C, + 0X29, 0X6C, 0X29, 0X6C, 0X29, 0X6C, 0X29, 0X6C, 0X29, 0X6C, 0X29, 0X6C, + 0X29, 0X6C, 0X29, 0X6C, 0X29, 0X6C, 0X29, 0X6C, 0X29, 0X6C, 0X21, 0X2B, + 0X21, 0X0C, 0X21, 0X4D, 0X29, 0X4D, 0X29, 0X4D, 0X21, 0X4D, 0X29, 0X4D, + 0X21, 0X4C, 0X21, 0X4C, 0X29, 0X4D, 0X29, 0X4D, 0X29, 0X2D, 0X29, 0X4D, + 0X29, 0X4D, 0X21, 0X2C, 0X21, 0X4C, 0X29, 0X4C, 0X29, 0X4B, 0X21, 0X2B, + 0X21, 0X6D, 0X21, 0X4D, 0X19, 0X0C, 0X10, 0XCA, 0X10, 0XA9, 0X08, 0X88, + 0X00, 0X66, 0X00, 0X01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X41, 0X08, 0X62, + 0X10, 0XA3, 0X4A, 0X29, 0X52, 0X8A, 0X52, 0X6A, 0X52, 0X6A, 0X52, 0X6A, + 0X5A, 0X8A, 0X18, 0XA2, 0X30, 0XE5, 0XAA, 0XCB, 0XCA, 0XC5, 0XD3, 0X64, + 0XD3, 0X64, 0XD3, 0X64, 0XC3, 0X64, 0XC3, 0X47, 0XC2, 0X4B, 0X80, 0XE8, + 0X30, 0XA7, 0X39, 0X27, 0X79, 0XE8, 0X71, 0XC8, 0X79, 0XE9, 0XA2, 0X88, + 0XAA, 0XE5, 0XBB, 0X65, 0X92, 0XC4, 0X18, 0XA5, 0X08, 0X86, 0X29, 0X26, + 0XAC, 0X84, 0X4B, 0XA9, 0X1A, 0X09, 0X2A, 0X48, 0X32, 0X88, 0X5B, 0X47, + 0X63, 0X06, 0X5A, 0X85, 0X31, 0X81, 0X51, 0X62, 0XD3, 0XE6, 0XD4, 0X05, + 0XE3, 0XA6, 0XA1, 0X23, 0X40, 0XA5, 0X31, 0X4B, 0X31, 0X6C, 0X51, 0X07, + 0X58, 0XA3, 0X00, 0X00, 0X29, 0X6D, 0X53, 0X38, 0X31, 0X0C, 0X41, 0X27, + 0X6A, 0X26, 0X49, 0X44, 0X1A, 0X26, 0X3C, 0X6C, 0X3A, 0X89, 0X4A, 0X29, + 0X21, 0X24, 0X00, 0X43, 0X11, 0X07, 0X08, 0XE5, 0X08, 0XE6, 0X11, 0X27, + 0X32, 0X2B, 0X32, 0X6C, 0X2A, 0X2B, 0X21, 0XEB, 0X21, 0XAA, 0X19, 0X26, + 0X08, 0XA4, 0X08, 0XA4, 0X08, 0XC4, 0X08, 0X84, 0X08, 0XA5, 0X11, 0X28, + 0X21, 0XAB, 0X29, 0X88, 0X31, 0X67, 0X21, 0X25, 0X32, 0X0B, 0X42, 0XAF, + 0X4B, 0X11, 0X42, 0XF1, 0X3A, 0X0A, 0X4A, 0X4A, 0X4A, 0X29, 0X62, 0XCA, + 0X42, 0X4B, 0X42, 0X49, 0X29, 0X04, 0X62, 0X6F, 0X6A, 0X6D, 0X6A, 0X8E, + 0X5A, 0X2B, 0X39, 0X24, 0X49, 0X66, 0X61, 0XCA, 0X69, 0XE9, 0X51, 0X64, + 0X49, 0X47, 0X51, 0X67, 0X59, 0XA5, 0X59, 0X85, 0X69, 0XE5, 0X6A, 0X05, + 0X5A, 0X49, 0X4A, 0XCC, 0X4A, 0XCC, 0X6A, 0X27, 0X51, 0X64, 0X39, 0X04, + 0X41, 0X25, 0X39, 0X26, 0X41, 0X87, 0X41, 0X87, 0X41, 0X66, 0X49, 0X43, + 0X20, 0XA2, 0X53, 0X0E, 0X63, 0X90, 0X53, 0X51, 0X3A, 0XF1, 0X3A, 0X8F, + 0X4A, 0XAD, 0X4A, 0XAD, 0X4A, 0XAD, 0X5B, 0X71, 0X53, 0X50, 0X42, 0XD1, + 0X29, 0XCA, 0X2A, 0X0B, 0X3A, 0X8E, 0X3A, 0X6D, 0X52, 0XCC, 0X5A, 0XCD, + 0X5A, 0XCD, 0X5A, 0XCD, 0X5B, 0X0F, 0X4A, 0XEF, 0X53, 0X30, 0X63, 0X0E, + 0X72, 0XEC, 0X5B, 0X4F, 0X6A, 0XED, 0X72, 0XCC, 0X6A, 0XCC, 0X6A, 0XEC, + 0X6A, 0XEC, 0X73, 0X0C, 0X63, 0X2E, 0X53, 0X0F, 0X4A, 0XEF, 0X42, 0X8E, + 0X4A, 0XAD, 0X5B, 0X70, 0X7C, 0X72, 0X5B, 0X2F, 0X53, 0X2F, 0X42, 0XCF, + 0X3A, 0XAF, 0X4B, 0X2F, 0X4B, 0X0F, 0X63, 0X0E, 0X63, 0X71, 0X5B, 0X4F, + 0X63, 0X4F, 0X63, 0X4F, 0X4B, 0X30, 0X53, 0X71, 0X5B, 0XF2, 0X63, 0XB1, + 0X63, 0X4F, 0X63, 0X4F, 0X63, 0X4F, 0X5B, 0X2E, 0X63, 0X4F, 0X63, 0X2E, + 0X5B, 0X0E, 0X5B, 0X4F, 0X5B, 0XB0, 0X5B, 0X70, 0X5B, 0X70, 0X5B, 0X90, + 0X5B, 0X90, 0X4B, 0X30, 0X42, 0XAF, 0X5B, 0X50, 0X53, 0X0F, 0X5B, 0X2F, + 0X5B, 0X50, 0X63, 0X70, 0X5B, 0X0F, 0X29, 0X66, 0X42, 0X2A, 0X39, 0XC7, + 0X39, 0XC7, 0X39, 0XC7, 0X31, 0X86, 0X29, 0X24, 0X29, 0X44, 0X29, 0X44, + 0X21, 0X45, 0X29, 0X66, 0X42, 0X6A, 0X42, 0X69, 0X6B, 0XF1, 0X63, 0X6F, + 0X63, 0X0D, 0X7B, 0X4F, 0X83, 0X0E, 0X82, 0XED, 0X92, 0X89, 0X8A, 0X89, + 0X8A, 0X89, 0X8A, 0XA9, 0X8A, 0XA9, 0X8A, 0XA9, 0X8B, 0X0C, 0X74, 0X12, + 0X73, 0XB1, 0X73, 0XB0, 0X73, 0XB0, 0X74, 0X12, 0X5B, 0X4F, 0X31, 0XEB, + 0X39, 0XEB, 0X3A, 0X0B, 0X42, 0X2C, 0X42, 0X6D, 0X3A, 0X4C, 0X3A, 0X4B, + 0X3A, 0X2C, 0X41, 0XA5, 0X52, 0XCC, 0X4A, 0XAE, 0X52, 0XCE, 0X5B, 0X30, + 0X53, 0X50, 0X4A, 0XCE, 0X4A, 0XCE, 0X3A, 0X6C, 0X42, 0X6C, 0X42, 0XCE, + 0X4A, 0XEF, 0X4A, 0XEF, 0X52, 0XEE, 0X42, 0XAE, 0X4A, 0X8D, 0X52, 0XEE, + 0X53, 0X0F, 0X4A, 0XAD, 0X4A, 0X8D, 0X52, 0XCF, 0X52, 0XCF, 0X52, 0XCF, + 0X52, 0XAE, 0X5A, 0XCE, 0X5A, 0XF0, 0X52, 0XF0, 0X53, 0X10, 0X4A, 0XF0, + 0X53, 0X11, 0X53, 0X11, 0X53, 0X31, 0X4A, 0XF0, 0X4A, 0XF0, 0X4B, 0X31, + 0X43, 0X11, 0X3B, 0X31, 0X3B, 0X32, 0X3B, 0X10, 0X3A, 0XF0, 0X3B, 0X10, + 0X43, 0X51, 0X43, 0X10, 0X42, 0XEF, 0X42, 0XF0, 0X3A, 0XD0, 0X3A, 0XAF, + 0X3A, 0XAE, 0X3A, 0X8D, 0X42, 0XEF, 0X53, 0X71, 0X7C, 0XB5, 0X6C, 0X33, + 0X4B, 0X10, 0X5B, 0X50, 0X5A, 0X8C, 0X62, 0X6B, 0X6B, 0X0E, 0X73, 0X6D, + 0X6B, 0X6D, 0X7B, 0XAE, 0X41, 0XE8, 0X42, 0X0A, 0X63, 0X0E, 0X5A, 0XEE, + 0X52, 0XCE, 0X3A, 0XD0, 0X3A, 0XB0, 0X3A, 0XAE, 0X4A, 0XCE, 0X5A, 0XEF, + 0X5A, 0XF0, 0X52, 0XCF, 0X5B, 0X30, 0X73, 0X90, 0X6B, 0XB0, 0X7B, 0X90, + 0X7B, 0X90, 0X83, 0XD1, 0X73, 0X4F, 0X6B, 0X4F, 0X83, 0XD1, 0X83, 0X6F, + 0X72, 0X09, 0X69, 0XE9, 0X72, 0XAC, 0X6A, 0X6B, 0X5A, 0X4A, 0X6B, 0X2F, + 0X6B, 0X70, 0X73, 0X0E, 0X72, 0XCC, 0X73, 0X91, 0X73, 0XB2, 0X73, 0X51, + 0X6A, 0XCE, 0X62, 0XCD, 0X73, 0XF3, 0X73, 0XF2, 0X7B, 0XF2, 0X62, 0XCE, + 0X72, 0XED, 0X62, 0XCD, 0X52, 0XAE, 0X5A, 0XCE, 0X5A, 0XCE, 0X6B, 0X0E, + 0X6B, 0X0E, 0X5A, 0XEE, 0X63, 0X0F, 0X63, 0X70, 0X63, 0X92, 0X63, 0X71, + 0X63, 0X4F, 0X63, 0X91, 0X63, 0X92, 0X5B, 0X51, 0X6B, 0X93, 0X6B, 0X92, + 0X5B, 0X31, 0X5B, 0X11, 0X5A, 0XF0, 0X6B, 0X51, 0X7B, 0X2F, 0X7B, 0X2F, + 0X7B, 0X0F, 0X73, 0X2F, 0X3A, 0X8C, 0X42, 0XCB, 0X4B, 0X0B, 0X32, 0X6D, + 0X2A, 0X6C, 0X2A, 0X4C, 0X31, 0XE9, 0X22, 0X2D, 0X3A, 0XCE, 0X2A, 0X6B, + 0X2A, 0X09, 0X3A, 0XA9, 0X21, 0XE9, 0X2A, 0X0A, 0X29, 0XE9, 0X29, 0XC9, + 0X21, 0XE9, 0X21, 0XE9, 0X19, 0XC9, 0X21, 0XC9, 0X32, 0X29, 0X3A, 0XCD, + 0X2A, 0X4C, 0X2A, 0X2B, 0X2B, 0X51, 0X2B, 0X30, 0X1A, 0X2A, 0X3A, 0X6B, + 0X31, 0XE9, 0X11, 0X46, 0X19, 0X66, 0X19, 0X66, 0X19, 0X86, 0X22, 0X0A, + 0X22, 0X8D, 0X2A, 0X4B, 0X21, 0XC7, 0X22, 0X08, 0X21, 0XC7, 0X22, 0X4B, + 0X3B, 0X73, 0X2A, 0X29, 0X22, 0X09, 0X22, 0X29, 0X19, 0XA6, 0X21, 0X25, + 0X39, 0XC8, 0X29, 0XC9, 0X3A, 0XAE, 0X32, 0X8C, 0X21, 0XC7, 0X19, 0XA7, + 0X29, 0X86, 0X32, 0XCD, 0X32, 0XCD, 0X32, 0X6B, 0X21, 0XE9, 0X22, 0X0A, + 0X32, 0X2A, 0X3A, 0X8B, 0X42, 0X8B, 0X32, 0XAD, 0X32, 0X8E, 0X32, 0XEF, + 0X2A, 0XAE, 0X2A, 0X4B, 0X53, 0X4F, 0X53, 0X70, 0X22, 0X2A, 0X3A, 0XEE, + 0X53, 0X50, 0X53, 0X71, 0X4B, 0X71, 0X53, 0X72, 0X53, 0X51, 0X53, 0X51, + 0X53, 0X52, 0X53, 0X51, 0X5B, 0X30, 0X72, 0XAE, 0X7A, 0X8E, 0X7A, 0X8E, + 0X7A, 0XAE, 0X52, 0X0A, 0X42, 0X0B, 0X42, 0X4D, 0X09, 0XED, 0X43, 0X0E, + 0X3A, 0X2A, 0X10, 0X83, 0X00, 0X00, 0X08, 0X41, 0X21, 0X46, 0X22, 0XCF, + 0X23, 0XF5, 0X4B, 0X71, 0X52, 0X6A, 0X42, 0X6B, 0X42, 0X6B, 0X3A, 0X8B, + 0X11, 0XA9, 0X00, 0XA6, 0X00, 0X21, 0X08, 0X62, 0X08, 0XA4, 0X10, 0XC4, + 0X10, 0XC4, 0X10, 0XC4, 0X10, 0XC4, 0X08, 0X84, 0X18, 0XC4, 0X29, 0X46, + 0X10, 0XA3, 0X10, 0X62, 0X10, 0XA2, 0X08, 0X62, 0X08, 0X62, 0X42, 0X6B, + 0X19, 0X26, 0X63, 0X6F, 0X7C, 0X32, 0X10, 0XE2, 0X19, 0X84, 0X32, 0X45, + 0X3A, 0X85, 0X3A, 0XA7, 0X32, 0X87, 0X32, 0X86, 0X32, 0X46, 0X42, 0XA6, + 0X42, 0XA6, 0X3A, 0X48, 0X21, 0X04, 0X28, 0XE5, 0X41, 0X4B, 0X52, 0X27, + 0XA3, 0X65, 0XA1, 0XE2, 0X58, 0X82, 0X08, 0XA4, 0X21, 0X66, 0X21, 0X25, + 0X21, 0X04, 0X2A, 0X2F, 0X43, 0X35, 0X43, 0X14, 0X3B, 0X34, 0X33, 0X15, + 0X42, 0X11, 0X59, 0X07, 0X59, 0X45, 0X30, 0XE5, 0X41, 0X25, 0X59, 0X46, + 0X41, 0XA8, 0X29, 0X66, 0X29, 0X45, 0X29, 0X46, 0X18, 0XC6, 0X18, 0XE6, + 0X21, 0X28, 0X28, 0XE3, 0X31, 0X25, 0X39, 0X46, 0X30, 0XA3, 0X20, 0XA5, + 0X20, 0XA4, 0X28, 0XE4, 0X21, 0X29, 0X21, 0X4C, 0X10, 0XAA, 0X19, 0X31, + 0X18, 0XA8, 0X30, 0XC3, 0X10, 0XA4, 0X11, 0X28, 0X19, 0X69, 0X21, 0X88, + 0X31, 0XC7, 0X31, 0X25, 0X29, 0XAC, 0X62, 0X67, 0X69, 0X25, 0X60, 0XA4, + 0X61, 0X24, 0X29, 0X67, 0X21, 0X26, 0X51, 0XA9, 0X59, 0X46, 0X10, 0X64, + 0X29, 0X06, 0X73, 0X71, 0X7B, 0XD3, 0X08, 0X62, 0X00, 0X20, 0X11, 0XA8, + 0X1A, 0X6B, 0X22, 0X4B, 0X22, 0X6B, 0X22, 0X8B, 0X1A, 0X2A, 0X21, 0XC9, + 0X2A, 0X0A, 0X10, 0XC4, 0X18, 0X81, 0X30, 0XE2, 0X41, 0XA6, 0X5A, 0XAB, + 0X5A, 0XCB, 0X62, 0XEC, 0X62, 0XEC, 0X5A, 0XCB, 0X6B, 0X4E, 0X73, 0XAF, + 0X6B, 0X4D, 0X63, 0X0C, 0X62, 0XEC, 0X5A, 0XCB, 0X5A, 0XEB, 0X5A, 0XEB, + 0X63, 0X2D, 0X63, 0X2D, 0X63, 0X2D, 0X63, 0X0D, 0X6B, 0X2D, 0X6B, 0X4E, + 0X73, 0X8F, 0X73, 0X8F, 0X7B, 0XB0, 0X7B, 0X6F, 0X7B, 0X90, 0X83, 0XD1, + 0X8B, 0XF1, 0X94, 0X12, 0X94, 0X52, 0X8B, 0XF0, 0X73, 0X4C, 0X5B, 0X0B, + 0X52, 0XEA, 0X52, 0XCA, 0X52, 0XCA, 0X4A, 0XC9, 0X4A, 0XC9, 0X4A, 0XC9, + 0X4A, 0XEB, 0X4A, 0XCA, 0X42, 0X89, 0X31, 0XC4, 0X31, 0XE5, 0X42, 0X05, + 0X39, 0XE4, 0X31, 0XC4, 0X19, 0X43, 0X3B, 0X0C, 0X53, 0X8E, 0X53, 0X8E, + 0X43, 0X0B, 0X31, 0XA4, 0X3A, 0X68, 0X43, 0X0B, 0X32, 0X88, 0X4C, 0X32, + 0X3B, 0X0B, 0X29, 0XC4, 0X29, 0XE4, 0X29, 0XC4, 0X3A, 0X05, 0X3A, 0X25, + 0X3A, 0X26, 0X3A, 0X25, 0X31, 0XE4, 0X32, 0X46, 0X42, 0XA9, 0X5B, 0X6C, + 0X5B, 0X4B, 0X53, 0X2A, 0X5B, 0X4B, 0X4A, 0XE9, 0X42, 0X67, 0X42, 0X47, + 0X42, 0X26, 0X42, 0X26, 0X42, 0X67, 0X42, 0X87, 0X4A, 0XA7, 0X52, 0XE9, + 0X52, 0XC9, 0X4A, 0XA8, 0X52, 0XA8, 0X73, 0X4B, 0X62, 0XE9, 0X3A, 0X25, + 0X63, 0X09, 0X73, 0X29, 0X52, 0XC8, 0X42, 0XA8, 0X3A, 0X26, 0X32, 0X05, + 0X32, 0X05, 0X31, 0XE5, 0X39, 0XC6, 0X42, 0X07, 0X39, 0XC7, 0X6A, 0XE9, + 0X93, 0X89, 0X9B, 0X68, 0X9B, 0X48, 0X9B, 0X47, 0X9B, 0X27, 0X93, 0X26, + 0X52, 0X87, 0X42, 0X47, 0X3A, 0X47, 0X3A, 0X27, 0X4A, 0XA8, 0X52, 0XA8, + 0X4A, 0X87, 0X3A, 0X66, 0X3A, 0X66, 0X32, 0X87, 0X2B, 0X08, 0X42, 0X47, + 0X6A, 0XCB, 0XA4, 0X70, 0XB5, 0X09, 0X64, 0X2D, 0X54, 0X0F, 0X54, 0X0E, + 0X53, 0XEE, 0X53, 0XCD, 0X4B, 0X8C, 0X4B, 0XAD, 0X4B, 0XEF, 0X4B, 0XEF, + 0X4B, 0XEF, 0X4B, 0XCE, 0X4B, 0XCE, 0X4B, 0XCE, 0X53, 0XCE, 0X54, 0X0F, + 0X53, 0XEF, 0X53, 0X6C, 0X42, 0XC9, 0X4B, 0X8C, 0X3A, 0XE8, 0X32, 0X86, + 0X2A, 0X67, 0X2A, 0X87, 0X2A, 0XA8, 0X32, 0XC8, 0X32, 0XC7, 0X32, 0X87, + 0X32, 0X66, 0X3A, 0X46, 0X8C, 0X06, 0X8C, 0X06, 0X5A, 0XA6, 0X39, 0X86, + 0X39, 0XCA, 0X42, 0X6D, 0X42, 0XAF, 0X4A, 0XCD, 0X42, 0XCC, 0X43, 0X0B, + 0X62, 0X69, 0X6A, 0X69, 0X8A, 0XE9, 0XA3, 0X48, 0XB4, 0X48, 0XAC, 0XE8, + 0X4A, 0XA6, 0X2A, 0X67, 0X32, 0XC8, 0X32, 0X67, 0X29, 0XE6, 0X3A, 0X66, + 0X3A, 0XA6, 0X32, 0X87, 0X32, 0X67, 0X2A, 0X87, 0X2A, 0XA7, 0X2A, 0X67, + 0X32, 0X67, 0X32, 0X67, 0X32, 0X86, 0X3A, 0XE8, 0X42, 0XA8, 0X42, 0X67, + 0X42, 0X47, 0X42, 0X47, 0X52, 0X88, 0X3A, 0XC8, 0X32, 0XC8, 0X3A, 0XC8, + 0X42, 0XC8, 0X3A, 0XC8, 0X32, 0X87, 0X32, 0X06, 0X3A, 0X06, 0X41, 0XE6, + 0X4A, 0X87, 0X52, 0XA8, 0X42, 0X27, 0X4A, 0X26, 0X42, 0X67, 0X32, 0XE9, + 0X32, 0XA9, 0X3A, 0X89, 0X3A, 0X89, 0X3A, 0X89, 0X29, 0XC7, 0X21, 0X45, + 0X21, 0X46, 0X21, 0X45, 0X10, 0XC3, 0X08, 0X41, 0X19, 0X66, 0X3A, 0X8C, + 0X32, 0X09, 0X29, 0XC8, 0X19, 0X45, 0X19, 0X25, 0X19, 0X25, 0X19, 0X45, + 0X08, 0XA2, 0X00, 0X41, 0X08, 0X41, 0X00, 0X41, 0X29, 0X85, 0X3A, 0X47, + 0X3A, 0X27, 0X42, 0X46, 0X4A, 0X46, 0X42, 0X46, 0X42, 0X26, 0X39, 0XA5, + 0X39, 0XA5, 0X41, 0XE6, 0X39, 0X85, 0X18, 0XC4, 0X19, 0X04, 0X21, 0X45, + 0X29, 0X45, 0X31, 0X85, 0X51, 0XE6, 0X59, 0XE6, 0X51, 0XE5, 0X51, 0XE5, + 0X51, 0XE5, 0X51, 0XC5, 0X49, 0XA5, 0X29, 0X44, 0X29, 0X24, 0X29, 0X85, + 0X29, 0X85, 0X29, 0XA5, 0X2A, 0X05, 0X29, 0XE5, 0X29, 0X65, 0X29, 0XE5, + 0X31, 0XE5, 0X4A, 0X06, 0X29, 0X65, 0X21, 0X04, 0X21, 0X04, 0X21, 0X03, + 0X21, 0X24, 0X21, 0X25, 0X31, 0X66, 0X31, 0X25, 0X5B, 0X0C, 0X4A, 0X49, + 0X28, 0XE4, 0X39, 0XC7, 0X53, 0X0C, 0X4A, 0X69, 0X39, 0XC6, 0X39, 0XC6, + 0X41, 0XE7, 0X49, 0XE6, 0X52, 0X28, 0X52, 0X27, 0X49, 0XE6, 0X52, 0X07, + 0X52, 0X06, 0X41, 0XA5, 0X41, 0XA5, 0X41, 0XA5, 0X41, 0XA5, 0X41, 0XE6, + 0X3A, 0X07, 0X52, 0X69, 0X4A, 0X89, 0X4A, 0X48, 0X49, 0XE6, 0X52, 0X48, + 0X4A, 0XCA, 0X4A, 0X07, 0X4A, 0X28, 0X52, 0X28, 0X52, 0X48, 0X52, 0X48, + 0X4A, 0X27, 0X4A, 0X69, 0X4A, 0XAA, 0X4A, 0X48, 0X4A, 0X27, 0X4A, 0X07, + 0X4A, 0X07, 0X49, 0XC6, 0X39, 0X85, 0X41, 0XA6, 0X49, 0XE7, 0X49, 0XE7, + 0X31, 0XE6, 0X29, 0XC6, 0X29, 0XE6, 0X29, 0X85, 0X29, 0X24, 0X31, 0XC7, + 0X43, 0X2C, 0X3A, 0XCB, 0X19, 0XC8, 0X19, 0XA9, 0X19, 0XA8, 0X21, 0X45, + 0X31, 0X44, 0X39, 0X86, 0X29, 0X87, 0X21, 0X87, 0X19, 0X88, 0X21, 0XC8, + 0X3A, 0XEA, 0X43, 0X29, 0X43, 0XA9, 0X43, 0XC9, 0X4B, 0XC9, 0X4B, 0XC9, + 0X4B, 0XCA, 0X43, 0XCA, 0X4B, 0XA9, 0X53, 0X28, 0X52, 0XE8, 0X53, 0X08, + 0X52, 0XC8, 0X42, 0X26, 0X4A, 0X26, 0X52, 0X66, 0X4A, 0X27, 0X41, 0XC6, + 0X32, 0X05, 0X3A, 0X46, 0X4A, 0X46, 0X4A, 0X66, 0X42, 0X87, 0X52, 0XA8, + 0X6A, 0XEA, 0X62, 0XA9, 0X5A, 0X68, 0X5A, 0X88, 0X62, 0XEA, 0X5A, 0X89, + 0X31, 0XE6, 0X31, 0XA5, 0X31, 0XA5, 0X29, 0X84, 0X42, 0X26, 0X42, 0X47, + 0X39, 0XE7, 0X5A, 0X69, 0X3A, 0X47, 0X32, 0X06, 0X42, 0X47, 0X42, 0XAA, + 0X42, 0X27, 0X39, 0XE6, 0X39, 0XA6, 0X4A, 0X07, 0X52, 0X68, 0X52, 0X88, + 0X52, 0X68, 0X4A, 0X47, 0X3A, 0X06, 0X32, 0X06, 0X3A, 0X26, 0X4A, 0X88, + 0X4A, 0X68, 0X3A, 0X69, 0X4A, 0XAA, 0X4A, 0X68, 0X4A, 0X68, 0X4A, 0X48, + 0X42, 0X67, 0X32, 0X26, 0X4A, 0X47, 0X62, 0XC8, 0X42, 0X27, 0X2A, 0X06, + 0X32, 0X06, 0X32, 0X26, 0X31, 0XE6, 0X31, 0XC6, 0X29, 0X85, 0X19, 0X03, + 0X19, 0X84, 0X19, 0X45, 0X19, 0XA7, 0X21, 0XC7, 0X21, 0XC8, 0X2A, 0X4B, + 0X32, 0XAE, 0X21, 0X88, 0X21, 0X88, 0X29, 0X63, 0X7B, 0XA8, 0X73, 0X87, + 0X7B, 0X88, 0X62, 0XA7, 0X39, 0XA7, 0X52, 0XAB, 0X3A, 0XEB, 0X2A, 0X49, + 0X31, 0XC7, 0X31, 0XC8, 0X21, 0X86, 0X29, 0X86, 0X73, 0X2D, 0X6B, 0X4E, + 0X52, 0XCC, 0X4A, 0X6A, 0X52, 0X8B, 0X52, 0X8B, 0X63, 0X2D, 0X5B, 0X0E, + 0X63, 0X0D, 0X63, 0X2D, 0X63, 0X2D, 0X5B, 0X0D, 0X63, 0X0D, 0X6B, 0X2D, + 0X5B, 0X0D, 0X63, 0X0C, 0X73, 0X4D, 0X6B, 0X0D, 0X5A, 0XCC, 0X63, 0X0C, + 0X62, 0XCC, 0X62, 0XCB, 0X6A, 0XEC, 0X6B, 0X0D, 0X6A, 0XEC, 0X63, 0X0C, + 0X5A, 0XCC, 0X73, 0X2D, 0X73, 0X6E, 0X73, 0X6E, 0X73, 0X4D, 0X73, 0X2D, + 0X7B, 0X8E, 0X83, 0XAE, 0X83, 0XAE, 0X83, 0XAE, 0X73, 0X2C, 0X6B, 0X0C, + 0X63, 0X0C, 0X63, 0X0D, 0X63, 0X0D, 0X63, 0X0D, 0X63, 0X0D, 0X63, 0X0D, + 0X6B, 0X2E, 0X6B, 0X2E, 0X6B, 0X0E, 0X6B, 0X0D, 0X6B, 0X0D, 0X6B, 0X4F, + 0X73, 0X91, 0X7B, 0XD2, 0X7B, 0XB2, 0X7B, 0XF3, 0X8C, 0X54, 0X94, 0X95, + 0X94, 0X95, 0X84, 0X53, 0X84, 0X53, 0X84, 0X32, 0X84, 0X52, 0X7C, 0X32, + 0X73, 0XD0, 0X52, 0XED, 0X3A, 0X0A, 0X31, 0XC9, 0X21, 0X05, 0X00, 0X21, + 0X08, 0X41, 0X10, 0XA4, 0X10, 0XE6, 0X11, 0X07, 0X19, 0X28, 0X19, 0X28, + 0X19, 0X48, 0X19, 0X89, 0X21, 0XEA, 0X21, 0XEA, 0X22, 0X0A, 0X22, 0X0A, + 0X19, 0XCA, 0X19, 0XEA, 0X22, 0X0B, 0X22, 0X4C, 0X2A, 0X8D, 0X11, 0X05, + 0X10, 0XE3, 0X32, 0XAB, 0X3A, 0XCC, 0X53, 0X4E, 0X53, 0X6E, 0X53, 0X8E, + 0X53, 0X6E, 0X43, 0X0C, 0X43, 0X0C, 0X43, 0X0C, 0X42, 0XCB, 0X4B, 0X0C, + 0X3A, 0XEC, 0X3A, 0XEC, 0X32, 0XEC, 0X3B, 0X4D, 0X43, 0X8D, 0X3A, 0XAB, + 0X32, 0XAB, 0X22, 0X2B, 0X2A, 0X4B, 0X2A, 0X2B, 0X2A, 0X4B, 0X43, 0X0E, + 0X43, 0X4E, 0X6C, 0X51, 0X7C, 0X92, 0X74, 0X51, 0X42, 0XAB, 0X64, 0X10, + 0X7D, 0X34, 0X74, 0X71, 0X6B, 0XEE, 0X63, 0X8E, 0X5A, 0XEC, 0X63, 0X6E, + 0X32, 0X08, 0X11, 0X04, 0X19, 0X25, 0X63, 0X6E, 0X3A, 0X49, 0X11, 0X45, + 0X53, 0X2E, 0X63, 0XD2, 0X4B, 0X2E, 0X63, 0XF0, 0X53, 0X4E, 0X19, 0X45, + 0X08, 0X20, 0X10, 0XC4, 0X19, 0X88, 0X19, 0X68, 0X19, 0X47, 0X19, 0X24, + 0X11, 0X04, 0X19, 0X45, 0X4B, 0X0C, 0X4B, 0X0C, 0X4B, 0X2C, 0X53, 0XAE, + 0X64, 0X10, 0X42, 0XCB, 0X3A, 0X49, 0X3A, 0X49, 0X3A, 0X49, 0X2A, 0X8C, + 0X2A, 0XEE, 0X2A, 0XEE, 0X43, 0X2D, 0X5B, 0X0C, 0X73, 0XEE, 0X52, 0XEB, + 0X2A, 0X8C, 0X3A, 0XEC, 0X5B, 0X0C, 0X6B, 0XAF, 0X5B, 0X2D, 0X43, 0X4E, + 0X4B, 0X6F, 0X53, 0XAE, 0X4A, 0XAA, 0X4A, 0XAA, 0X4A, 0XAA, 0X4A, 0XCA, + 0X19, 0X04, 0X4A, 0X25, 0X62, 0XE7, 0X5A, 0XC6, 0X52, 0XE8, 0X53, 0X09, + 0X5A, 0XC7, 0X52, 0X85, 0X5A, 0XC7, 0X42, 0XAB, 0X4A, 0X86, 0X52, 0XA5, + 0X52, 0X86, 0X52, 0X66, 0X4A, 0X65, 0X52, 0X85, 0X5A, 0X84, 0X42, 0X25, + 0X42, 0X25, 0X4A, 0X66, 0X4A, 0X66, 0X4A, 0X66, 0X52, 0XA6, 0X6B, 0X06, + 0X4A, 0XA9, 0X4A, 0X88, 0X4A, 0X87, 0X42, 0XA9, 0X3A, 0XCB, 0X3A, 0X89, + 0X3A, 0X69, 0X2A, 0X4B, 0X22, 0X8D, 0X22, 0XAE, 0X22, 0XCF, 0X22, 0X6D, + 0X19, 0X47, 0X19, 0X26, 0X11, 0X26, 0X19, 0X26, 0X29, 0X86, 0X29, 0X87, + 0X19, 0X67, 0X19, 0X86, 0X21, 0XC9, 0X32, 0X4C, 0X32, 0X4B, 0X32, 0X4B, + 0X21, 0XEA, 0X09, 0X48, 0X11, 0X89, 0X11, 0XCA, 0X11, 0XA9, 0X11, 0XA9, + 0X1A, 0X0B, 0X11, 0XCB, 0X1A, 0X2B, 0X22, 0XCE, 0X22, 0X8D, 0X19, 0X88, + 0X29, 0XC9, 0X29, 0XEA, 0X2A, 0X4C, 0X3A, 0XCF, 0X3A, 0XAE, 0X29, 0XC9, + 0X21, 0X89, 0X21, 0XA9, 0X11, 0XA9, 0X11, 0XA9, 0X19, 0X89, 0X19, 0X68, + 0X11, 0X69, 0X11, 0XCB, 0X11, 0XEC, 0X1A, 0X2D, 0X22, 0X8E, 0X1A, 0X2C, + 0X1A, 0X2C, 0X22, 0X8E, 0X22, 0X4C, 0X19, 0XCC, 0X22, 0X4E, 0X22, 0X8F, + 0X19, 0XAA, 0X2A, 0XEF, 0X2B, 0X11, 0X19, 0XCB, 0X22, 0X2C, 0X22, 0X4D, + 0X19, 0XA9, 0X19, 0XA9, 0X1A, 0X0B, 0X11, 0XA9, 0X19, 0XA9, 0X19, 0XA9, + 0X19, 0X89, 0X21, 0XCA, 0X22, 0X0B, 0X21, 0XEA, 0X19, 0X68, 0X1A, 0X0B, + 0X19, 0XEA, 0X19, 0XAA, 0X19, 0XCB, 0X22, 0X8E, 0X1A, 0X2D, 0X11, 0XA9, + 0X11, 0X68, 0X11, 0X47, 0X11, 0X05, 0X11, 0X26, 0X19, 0X25, 0X19, 0X25, + 0X19, 0X04, 0X19, 0X05, 0X19, 0X05, 0X19, 0X25, 0X19, 0XA8, 0X21, 0XC9, + 0X21, 0XA8, 0X21, 0XA8, 0X1A, 0X2B, 0X1A, 0X8E, 0X1A, 0X6D, 0X1A, 0X4D, + 0X42, 0XAD, 0X52, 0XCD, 0X5A, 0XCD, 0X5A, 0X8C, 0X4A, 0X2B, 0X4A, 0X0A, + 0X6A, 0XCC, 0X62, 0XAC, 0X4A, 0X8B, 0X52, 0X8C, 0X52, 0XAC, 0X52, 0XCC, + 0X3A, 0X09, 0X08, 0X41, 0X08, 0X62, 0X08, 0X83, 0X08, 0XA4, 0X08, 0XA4, + 0X10, 0X83, 0X08, 0X83, 0X08, 0X83, 0X10, 0XC4, 0X19, 0X46, 0X19, 0X46, + 0X19, 0X46, 0X10, 0XE4, 0X08, 0X62, 0X08, 0X62, 0X08, 0X62, 0X00, 0X21, + 0X00, 0X00, 0X08, 0X42, 0X08, 0X63, 0X08, 0X83, 0X10, 0XA3, 0X10, 0XA4, + 0X10, 0XC4, 0X18, 0XE4, 0X18, 0XE4, 0X18, 0XE3, 0X20, 0XE2, 0X29, 0X22, + 0X62, 0X24, 0X72, 0X65, 0X7A, 0XA5, 0X8A, 0XE5, 0X7A, 0XC4, 0X72, 0XA5, + 0X72, 0XA4, 0X8A, 0XC5, 0X72, 0XA5, 0X49, 0XC4, 0X51, 0XE4, 0X5A, 0X04, + 0X51, 0XE4, 0X31, 0X85, 0X29, 0X85, 0X19, 0X25, 0X11, 0X05, 0X10, 0XC5, + 0X19, 0X25, 0X29, 0XC6, 0X42, 0X47, 0X42, 0X67, 0X21, 0X86, 0X08, 0XC5, + 0X08, 0XA5, 0X08, 0XA4, 0X08, 0X84, 0X08, 0X84, 0X08, 0X84, 0X08, 0XA4, + 0X08, 0XA4, 0X08, 0X83, 0X08, 0X83, 0X10, 0XC4, 0X10, 0XE4, 0X08, 0XC4, + 0X39, 0XC7, 0X42, 0X29, 0X4A, 0X4A, 0X42, 0X29, 0X2A, 0X08, 0X3A, 0X29, + 0X42, 0X29, 0X32, 0X29, 0X2A, 0X08, 0X3A, 0X08, 0X42, 0X4A, 0X3A, 0XAB, + 0X3A, 0X6A, 0X42, 0X29, 0X42, 0X08, 0X31, 0XA6, 0X21, 0X24, 0X21, 0X24, + 0X08, 0XA3, 0X11, 0X04, 0X29, 0XA6, 0X31, 0XA6, 0X39, 0XC6, 0X29, 0X65, + 0X19, 0X25, 0X41, 0XC7, 0X52, 0X49, 0X21, 0X46, 0X19, 0X26, 0X19, 0X66, + 0X5A, 0X89, 0X51, 0XE7, 0X31, 0X25, 0X39, 0X45, 0X39, 0XA7, 0X73, 0X0B, + 0X4A, 0X08, 0X62, 0XAA, 0X6A, 0XEB, 0X6A, 0XAA, 0X6A, 0XCB, 0X6A, 0XCB, + 0X73, 0X0C, 0X73, 0X0B, 0X5A, 0X89, 0X41, 0XC7, 0X72, 0XC9, 0X6A, 0XA9, + 0X42, 0X08, 0X31, 0X86, 0X39, 0XC7, 0X4A, 0X28, 0X41, 0XE7, 0X4A, 0X28, + 0X5A, 0XCA, 0X5A, 0XA9, 0X52, 0X89, 0X4A, 0X69, 0X42, 0X27, 0X39, 0XE7, + 0X29, 0XA8, 0X29, 0XC8, 0X19, 0X67, 0X19, 0X87, 0X29, 0XE9, 0X29, 0XE9, + 0X52, 0XCC, 0X52, 0X8A, 0X08, 0XA4, 0X10, 0XE5, 0X21, 0X26, 0X41, 0XCA, + 0X4A, 0X2B, 0X4A, 0X4B, 0X42, 0XAE, 0X39, 0XCA, 0X39, 0XAA, 0X41, 0XEB, + 0X39, 0XAB, 0X4A, 0X4B, 0X52, 0X4C, 0X41, 0XEA, 0X31, 0XE7, 0X42, 0X68, + 0X62, 0X8A, 0X52, 0X69, 0X5A, 0X8A, 0X63, 0X0B, 0X73, 0X8D, 0X53, 0X0C, + 0X5A, 0XCB, 0X52, 0X6A, 0X4A, 0X0B, 0X4A, 0X4B, 0X63, 0X0B, 0X6A, 0XEC, + 0X73, 0X2B, 0X73, 0X2B, 0X62, 0XAB, 0X62, 0XAB, 0X6A, 0XAB, 0X31, 0X66, + 0X29, 0X45, 0X31, 0X86, 0X31, 0X25, 0X29, 0X45, 0X31, 0X86, 0X52, 0X69, + 0X52, 0X69, 0X42, 0X08, 0X42, 0X49, 0X42, 0X4A, 0X4A, 0X6A, 0X42, 0X09, + 0X39, 0XE8, 0X32, 0X2B, 0X29, 0XC9, 0X31, 0X45, 0X4A, 0X29, 0X42, 0X08, + 0X4A, 0X28, 0X41, 0XA6, 0X41, 0XC7, 0X39, 0XE8, 0X39, 0XE8, 0X31, 0XE9, + 0X4A, 0X69, 0X4A, 0X69, 0X42, 0X29, 0X42, 0X28, 0X4A, 0X48, 0X42, 0X49, + 0X42, 0X4A, 0X4A, 0X6A, 0X4A, 0X6B, 0X4A, 0X6B, 0X4A, 0X6B, 0X4A, 0X8A, + 0X4A, 0XAA, 0X4A, 0X49, 0X42, 0X29, 0X4A, 0X8A, 0X4A, 0X8A, 0X4A, 0XAA, + 0X5A, 0XCB, 0X52, 0X8A, 0X5A, 0XAA, 0X5A, 0XAA, 0X52, 0X89, 0X4A, 0X48, + 0X29, 0X65, 0X31, 0X85, 0X5A, 0XCA, 0X52, 0XAB, 0X6B, 0X0B, 0X7B, 0X4A, + 0X41, 0XC6, 0X72, 0XE9, 0X73, 0X2B, 0X29, 0X66, 0X10, 0X83, 0X10, 0X82, + 0X52, 0X48, 0X7B, 0X2B, 0X6B, 0X0A, 0X73, 0X2B, 0X52, 0X89, 0X5A, 0XCA, + 0X5A, 0XAA, 0X6A, 0XC9, 0X73, 0X0A, 0X5A, 0XE9, 0X73, 0X4B, 0X41, 0XC6, + 0X62, 0X88, 0X8B, 0X6B, 0X52, 0X27, 0X41, 0XC6, 0X72, 0XE9, 0X6A, 0XA9, + 0X6A, 0XEA, 0X8B, 0X6A, 0X8B, 0X4A, 0X83, 0X09, 0X7B, 0X0A, 0X83, 0X4A, + 0X8B, 0XAB, 0X83, 0X4A, 0X73, 0X4C, 0X6B, 0X2B, 0X62, 0XCA, 0X6B, 0X0B, + 0X6B, 0X0C, 0X52, 0X48, 0X6B, 0X0C, 0X7B, 0X2A, 0X8B, 0XAB, 0X73, 0X2C, + 0X62, 0XCA, 0X4A, 0X68, 0X52, 0X89, 0X4A, 0X47, 0X41, 0XC7, 0X52, 0X48, + 0X4A, 0X67, 0X62, 0XEA, 0X72, 0XE9, 0X6A, 0XE9, 0X52, 0X69, 0X62, 0XA9, + 0X6A, 0XC8, 0X5A, 0XA9, 0X63, 0X0B, 0X52, 0XAB, 0X5A, 0XA9, 0X63, 0X0B, + 0X62, 0XEA, 0X62, 0XEA, 0X62, 0XEA, 0X62, 0XCA, 0X6B, 0X0B, 0X6B, 0X2B, + 0X7B, 0X6C, 0X83, 0XCE, 0X7B, 0X6B, 0X7B, 0X2B, 0X41, 0XE7, 0X4A, 0X48, + 0X7B, 0XD0, 0X7B, 0XD0, 0X62, 0XEB, 0X6C, 0X13, 0X74, 0X75, 0X73, 0X8D, + 0X7B, 0X2A, 0X51, 0XA5, 0X5A, 0X27, 0X62, 0X88, 0X6A, 0XA9, 0X83, 0X4B, + 0X72, 0XA8, 0X6A, 0X28, 0X8B, 0X4E, 0X6A, 0X89, 0X62, 0X48, 0X83, 0X8D, + 0X62, 0X89, 0X62, 0X88, 0X62, 0X26, 0X5A, 0X68, 0X52, 0XCB, 0X52, 0X8A, + 0X4A, 0X28, 0X73, 0X2B, 0X94, 0X2F, 0X39, 0XA6, 0X4A, 0X48, 0X7B, 0X6C, + 0X73, 0X6C, 0X6B, 0X2B, 0X83, 0XCC, 0X8B, 0XCC, 0X8B, 0XCC, 0X73, 0X4B, + 0X62, 0XEB, 0X62, 0XEB, 0X62, 0XEA, 0X73, 0X4B, 0X83, 0XCD, 0X6B, 0X2B, + 0X7B, 0X8C, 0X83, 0XCD, 0X73, 0X4C, 0X83, 0XAD, 0X63, 0X0B, 0X6B, 0X2B, + 0X52, 0XA9, 0X73, 0X2A, 0X6B, 0X2B, 0X4A, 0X8A, 0X5A, 0X8A, 0X5A, 0X8A, + 0X52, 0X6A, 0X73, 0X4C, 0X6B, 0X2B, 0X6B, 0X0C, 0X7B, 0X2D, 0X41, 0XC8, + 0X31, 0XC8, 0X5A, 0XCB, 0X7B, 0X8C, 0X63, 0X0B, 0X7B, 0X8C, 0X5A, 0XA9, + 0X73, 0X4C, 0X8B, 0XCE, 0X73, 0X4C, 0X4A, 0X28, 0X31, 0XE9, 0X52, 0XAB, + 0X5B, 0X2D, 0X52, 0XEC, 0X6B, 0X4E, 0X6B, 0X4E, 0X4A, 0X89, 0X4A, 0X8A, + 0X42, 0X4A, 0X4A, 0X49, 0X4A, 0X69, 0X4A, 0X69, 0X52, 0X8A, 0X6B, 0X6D, + 0X52, 0X08, 0X5A, 0X49, 0X5A, 0X6A, 0X5A, 0X6A, 0X5A, 0X69, 0X62, 0XAB, + 0X73, 0X0C, 0X6A, 0XEC, 0X5A, 0X6A, 0X5A, 0X8A, 0X5A, 0X8A, 0X52, 0X6A, + 0X6B, 0X2C, 0X5A, 0XCB, 0X42, 0X29, 0X6B, 0X0B, 0X63, 0X2D, 0X53, 0X0D, + 0X4A, 0X8A, 0X39, 0XC7, 0X42, 0X29, 0X4A, 0XCC, 0X42, 0X8B, 0X5A, 0XEB, + 0X52, 0XAA, 0X32, 0X29, 0X42, 0X8B, 0X3A, 0X6C, 0X3A, 0X0A, 0X3A, 0X6D, + 0X3A, 0X8E, 0X32, 0X8A, 0X3A, 0X6B, 0X42, 0X6C, 0X42, 0X6C, 0X2A, 0X0D, + 0X42, 0X4D, 0X52, 0X8D, 0X52, 0X2A, 0X52, 0X2A, 0X5A, 0X6A, 0X62, 0XCB, + 0X6A, 0XCB, 0X6B, 0X6F, 0X6B, 0X4E, 0X73, 0X4E, 0X4A, 0X0A, 0X39, 0X87, + 0X62, 0XAB, 0X6A, 0XCC, 0X6B, 0X0C, 0X6B, 0X2D, 0X63, 0X4F, 0X73, 0X2F, + 0X6A, 0XED, 0X6A, 0XCC, 0X63, 0X2F, 0X73, 0X6F, 0X73, 0X2D, 0X83, 0XAF, + 0X6A, 0XED, 0X62, 0XCD, 0X4A, 0X09, 0X5A, 0X8C, 0X6B, 0X71, 0X5B, 0X32, + 0X6B, 0X73, 0X5A, 0XEF, 0X5A, 0XCF, 0X5B, 0X95, 0X5A, 0X4D, 0X5A, 0X2B, + 0X5A, 0X4B, 0X5A, 0X6B, 0X5A, 0X6C, 0X52, 0X0B, 0X52, 0X2B, 0X49, 0XCA, + 0X41, 0X8A, 0X49, 0XAA, 0X5A, 0X4C, 0X53, 0X10, 0X5B, 0X11, 0X62, 0XCF, + 0X7B, 0X8F, 0X63, 0X2E, 0X63, 0X2D, 0X83, 0XF0, 0X94, 0X93, 0X52, 0XAD, + 0X21, 0X08, 0X5A, 0XAF, 0X31, 0XA6, 0X21, 0X44, 0X21, 0X25, 0X29, 0X46, + 0X29, 0X26, 0X21, 0X06, 0X20, 0XE6, 0X29, 0X26, 0X29, 0X26, 0X29, 0X26, + 0X21, 0X06, 0X19, 0X06, 0X29, 0X68, 0X31, 0X89, 0X31, 0X68, 0X29, 0X67, + 0X31, 0XAA, 0X31, 0XA9, 0X31, 0X68, 0X31, 0X89, 0X29, 0X67, 0X29, 0X68, + 0X29, 0X69, 0X29, 0X27, 0X29, 0X07, 0X29, 0X27, 0X29, 0X69, 0X29, 0X67, + 0X29, 0X67, 0X29, 0X67, 0X29, 0X68, 0X31, 0X89, 0X31, 0X89, 0X29, 0X67, + 0X29, 0X67, 0X29, 0X47, 0X00, 0X00, 0X21, 0X88, 0X32, 0X4D, 0X32, 0X4D, + 0X32, 0X90, 0X42, 0XCF, 0X6B, 0X0D, 0X6B, 0X0C, 0X42, 0X2B, 0X29, 0X68, + 0X59, 0XC4, 0X59, 0XA3, 0X59, 0XC4, 0X51, 0X83, 0X49, 0X63, 0X49, 0X63, + 0X49, 0X43, 0X51, 0X84, 0X5A, 0X06, 0X49, 0X63, 0X49, 0X42, 0X41, 0X63, + 0X41, 0X64, 0X39, 0X64, 0X39, 0X64, 0X39, 0X64, 0X39, 0X85, 0X39, 0X85, + 0X39, 0X85, 0X41, 0XC6, 0X4A, 0X07, 0X41, 0XE7, 0X4A, 0X07, 0X41, 0XC5, + 0X49, 0XA4, 0X49, 0X84, 0X41, 0XC6, 0X41, 0XE7, 0X52, 0X47, 0X62, 0XA9, + 0X62, 0XC9, 0X49, 0XE5, 0X4A, 0X06, 0X4A, 0X06, 0X39, 0X43, 0X52, 0X26, + 0X52, 0X26, 0X49, 0X83, 0X49, 0X83, 0X52, 0X26, 0X49, 0X84, 0X49, 0XA4, + 0X52, 0X46, 0X52, 0X26, 0X52, 0X67, 0X52, 0X47, 0X52, 0X67, 0X4A, 0X06, + 0X39, 0X84, 0X41, 0X84, 0X49, 0XC6, 0X49, 0XC6, 0X49, 0XE6, 0X41, 0X85, + 0X41, 0XE6, 0X42, 0X07, 0X4A, 0X07, 0X52, 0X06, 0X52, 0X06, 0X52, 0X06, + 0X18, 0XE3, 0X2A, 0X08, 0X32, 0X28, 0X32, 0X08, 0X32, 0X29, 0X4A, 0X28, + 0X42, 0X07, 0X42, 0X07, 0X42, 0X07, 0X31, 0XC5, 0X4A, 0X8A, 0X5B, 0X4E, + 0X5B, 0X2E, 0X3A, 0X8C, 0X32, 0X8B, 0X3B, 0X2C, 0X33, 0X4C, 0X2B, 0X2B, + 0X22, 0XEB, 0X1A, 0XAA, 0X22, 0X28, 0X22, 0X28, 0X32, 0X8A, 0X3A, 0XCB, + 0X3A, 0X4A, 0X3A, 0X6A, 0X42, 0X6A, 0X29, 0X68, 0X3A, 0X2A, 0X10, 0XE5, + 0X10, 0X41, 0X20, 0X42, 0X20, 0X64, 0X18, 0X64, 0X10, 0X64, 0X18, 0X84, + 0X30, 0X63, 0X38, 0X63, 0X30, 0X62, 0X18, 0X63, 0X10, 0XA4, 0X10, 0XA4, + 0X18, 0XA3, 0X30, 0X82, 0X39, 0X05, 0X22, 0X69, 0X22, 0X69, 0X2A, 0X89, + 0X2A, 0XEB, 0X33, 0X0C, 0X42, 0X49, 0X6A, 0XEA, 0X5B, 0X0B, 0X4A, 0XAB, + 0X3A, 0X4A, 0X32, 0X6A, 0X3A, 0X89, 0X4A, 0XAB, 0X4A, 0XAB, 0X2A, 0X69, + 0X42, 0XCB, 0X3A, 0XA9, 0X5B, 0X2D, 0X6B, 0X8E, 0X7C, 0X31, 0X7B, 0XEE, + 0X7C, 0X51, 0X73, 0XF0, 0X63, 0X6E, 0X6B, 0X6E, 0X6B, 0X6E, 0X63, 0X8E, + 0X53, 0X4C, 0X52, 0XCB, 0X5B, 0X2D, 0X5A, 0XA9, 0X52, 0X8A, 0X31, 0XC7, + 0X63, 0X6E, 0X6B, 0XAF, 0X73, 0X8E, 0X6B, 0X6E, 0X63, 0X2E, 0X6C, 0X31, + 0X53, 0X2A, 0X4B, 0X0A, 0X4B, 0X09, 0X4A, 0XEA, 0X5A, 0XED, 0X5B, 0X0C, + 0X5A, 0XEA, 0X4B, 0X2B, 0X4A, 0XAA, 0X63, 0X4F, 0X5B, 0X0A, 0X5B, 0X2B, + 0X63, 0X6E, 0X63, 0X2E, 0X63, 0X2E, 0X63, 0X6E, 0X63, 0X8E, 0X53, 0X4D, + 0X3A, 0XAA, 0X53, 0X0C, 0X4A, 0X68, 0X4A, 0XAA, 0X6B, 0X0B, 0X63, 0X6E, + 0X6C, 0X52, 0X6B, 0X8E, 0X6A, 0XCA, 0X73, 0XCF, 0X21, 0XE9, 0X5B, 0X0E, + 0X73, 0XAF, 0X4A, 0X29, 0X39, 0XC7, 0X62, 0XEB, 0X5A, 0X49, 0X39, 0XA5, + 0X52, 0X08, 0X39, 0XA7, 0X41, 0XE7, 0X49, 0XE7, 0X4A, 0X49, 0X6A, 0XEB, + 0X51, 0XE7, 0X5A, 0XEC, 0X4A, 0X49, 0X4A, 0X08, 0X4A, 0X09, 0X62, 0XCA, + 0X7B, 0X2A, 0X5A, 0XAA, 0X5A, 0XAA, 0X5A, 0XA9, 0X5A, 0X88, 0X5A, 0X68, + 0X62, 0XA8, 0X62, 0XC9, 0X52, 0X48, 0X41, 0XA6, 0X4A, 0X27, 0X52, 0X88, + 0X39, 0XA7, 0X41, 0XC8, 0X8B, 0X8B, 0X83, 0X4A, 0X41, 0X88, 0X5A, 0X49, + 0X83, 0X8B, 0X6B, 0X0A, 0X4A, 0X69, 0X63, 0X0C, 0X62, 0XA9, 0X83, 0X6B, + 0X8B, 0X8C, 0X94, 0X0F, 0X9C, 0X4F, 0X4A, 0X4A, 0X62, 0XCA, 0XA4, 0X6F, + 0X6A, 0XEA, 0X5A, 0X67, 0X8B, 0XCD, 0X8B, 0XEE, 0X52, 0X49, 0X73, 0X2B, + 0X5A, 0X67, 0X62, 0XE9, 0X6B, 0X0A, 0X39, 0X86, 0X39, 0X85, 0X62, 0XEA, + 0X8B, 0XAC, 0X73, 0X0A, 0X7B, 0X4A, 0X83, 0X6B, 0X93, 0X8B, 0X5A, 0X68, + 0X29, 0X87, 0X19, 0X26, 0X10, 0XE5, 0X18, 0XA4, 0X18, 0XC3, 0X19, 0X47, + 0X10, 0XC4, 0X18, 0XE4, 0X21, 0X45, 0X63, 0X4C, 0X73, 0XAE, 0X73, 0XCE, + 0X9C, 0X70, 0X73, 0X4C, 0X18, 0XE4, 0X63, 0X0C, 0X84, 0X2F, 0X6B, 0X8E, + 0X6B, 0XAF, 0X7C, 0X0F, 0X53, 0X0E, 0X32, 0X4B, 0X53, 0X2D, 0X6B, 0XAE, + 0X5B, 0X0C, 0X42, 0X49, 0X42, 0X29, 0X5B, 0X0C, 0X29, 0XC7, 0X21, 0XE8, + 0X3B, 0X0D, 0X53, 0X0F, 0X53, 0X0F, 0X63, 0X0E, 0X62, 0XEB, 0X53, 0X0D, + 0X43, 0X2F, 0X3A, 0X8B, 0X3A, 0X6A, 0X2A, 0X4A, 0X52, 0XEC, 0X42, 0XEC, + 0X63, 0X6F, 0X63, 0X6E, 0X63, 0X0D, 0X6B, 0X0D, 0X6B, 0X4E, 0X4A, 0XEC, + 0X63, 0X4D, 0X5B, 0X2D, 0X53, 0X0C, 0X4A, 0XEC, 0X53, 0X0C, 0X6B, 0X8E, + 0X73, 0XAE, 0X3A, 0XAC, 0X39, 0XA4, 0X5A, 0X67, 0X6B, 0X0C, 0X4A, 0XEC, + 0X33, 0X4F, 0X3A, 0XED, 0X5A, 0XCB, 0X42, 0X8A, 0X4A, 0XCB, 0X42, 0XCB, + 0X43, 0X2E, 0X32, 0X8A, 0X32, 0X6A, 0X31, 0XC9, 0X32, 0X4B, 0X31, 0XEA, + 0X3A, 0X8B, 0X53, 0X2C, 0X42, 0XEC, 0X42, 0XEC, 0X31, 0XC9, 0X39, 0XA9, + 0X3A, 0X8C, 0X3A, 0X8B, 0X4A, 0XCB, 0X3A, 0X0A, 0X42, 0X09, 0X32, 0X0A, + 0X42, 0X6A, 0X6B, 0XAE, 0X5B, 0X4F, 0X5B, 0X4D, 0X6B, 0X6F, 0X53, 0XF1, + 0X6B, 0XF0, 0X6B, 0X6F, 0X6B, 0X4E, 0X4A, 0X8A, 0X4A, 0XAB, 0X43, 0XAF, + 0X3A, 0XCC, 0X53, 0X0C, 0X5B, 0X2D, 0X53, 0X6E, 0X5B, 0X90, 0X5B, 0X6F, + 0X63, 0X8D, 0X5B, 0XF0, 0X54, 0X31, 0X5B, 0XCF, 0X63, 0X2C, 0X5C, 0X31, + 0X63, 0X4D, 0X5B, 0X8E, 0X63, 0XAE, 0X52, 0XCA, 0X52, 0X6A, 0X6B, 0XF1, + 0X74, 0X54, 0X63, 0X90, 0X4A, 0XAC, 0X62, 0X8C, 0X7B, 0X4F, 0X93, 0X0F, + 0X9A, 0XEE, 0X9B, 0X0F, 0XA2, 0XF0, 0XA3, 0X10, 0X93, 0X4F, 0X7A, 0XCE, + 0X4A, 0X0A, 0X21, 0X04, 0X5A, 0X4B, 0X7A, 0XAD, 0X7B, 0X0E, 0XB4, 0X53, + 0X69, 0XC7, 0X59, 0X66, 0X49, 0XA8, 0X49, 0X66, 0X42, 0X0A, 0X42, 0X6B, + 0X4A, 0X2A, 0X52, 0X29, 0X5A, 0X8A, 0X4A, 0X09, 0X41, 0XC7, 0X62, 0XCB, + 0X5A, 0X4A, 0X41, 0XA7, 0X39, 0XA5, 0X39, 0XC5, 0X49, 0XC7, 0X5A, 0X0A, + 0X49, 0XA8, 0X49, 0XA8, 0X8A, 0X6E, 0X8A, 0X8E, 0X62, 0X2C, 0X39, 0XEA, + 0X5A, 0X8C, 0X5A, 0X6B, 0X52, 0XAD, 0X3B, 0X31, 0X32, 0XCF, 0X19, 0XCB, + 0X2A, 0X4E, 0X42, 0XF0, 0X3A, 0XAE, 0X42, 0XCF, 0X32, 0X4C, 0X09, 0X25, + 0X09, 0X05, 0X31, 0X65, 0X39, 0X85, 0X21, 0X04, 0X08, 0X41, 0X29, 0X86, + 0X4A, 0XAB, 0X42, 0X8A, 0X4A, 0X8A, 0X42, 0X2A, 0X31, 0XA8, 0X29, 0X88, + 0X21, 0X47, 0X31, 0X87, 0X5A, 0X6A, 0X31, 0X88, 0X21, 0X48, 0X3A, 0X2B, + 0X29, 0X88, 0X10, 0X62, 0X08, 0X62, 0X10, 0X82, 0X08, 0X41, 0X08, 0XE5, + 0X11, 0X48, 0X08, 0XA3, 0X08, 0X62, 0X08, 0X62, 0X08, 0X62, 0X18, 0XE3, + 0X21, 0X24, 0X31, 0X65, 0X31, 0X87, 0X31, 0X24, 0X31, 0X65, 0X39, 0XA7, + 0X41, 0X87, 0X29, 0X04, 0X31, 0X25, 0X39, 0X66, 0X41, 0X67, 0X20, 0XC4, + 0X31, 0XC7, 0X5A, 0X8A, 0X52, 0X6A, 0X39, 0XE9, 0X3A, 0X08, 0X21, 0X67, + 0X21, 0X87, 0X39, 0XE9, 0X42, 0X2A, 0X42, 0X09, 0X42, 0X4B, 0X41, 0XEA, + 0X42, 0X4A, 0X42, 0X2A, 0X31, 0X88, 0X39, 0XEA, 0X42, 0X4B, 0X4A, 0X4A, + 0X4A, 0X09, 0X4A, 0X2A, 0X4A, 0X29, 0X42, 0X0A, 0X42, 0X8A, 0X42, 0XAA, + 0X42, 0X4A, 0X42, 0X29, 0X41, 0XC7, 0X39, 0X47, 0X52, 0X08, 0X49, 0XA7, + 0X62, 0X07, 0X59, 0XE7, 0X4A, 0X49, 0X39, 0XE8, 0X39, 0XE8, 0X52, 0X8A, + 0X31, 0XC8, 0X29, 0X67, 0X4A, 0X6A, 0X39, 0XC8, 0X10, 0XA3, 0X10, 0XA4, + 0X08, 0XA4, 0X10, 0XA4, 0X10, 0XE5, 0X00, 0XC5, 0X00, 0XC4, 0X00, 0XC4, + 0X00, 0XC4, 0X00, 0XC4, 0X00, 0XC4, 0X00, 0XC5, 0X08, 0XC5, 0X08, 0XE5, + 0X08, 0XE5, 0X08, 0XE5, 0X19, 0X05, 0X19, 0X05, 0X11, 0X05, 0X11, 0X05, + 0X10, 0XE5, 0X10, 0XC5, 0X10, 0XE6, 0X10, 0XE6, 0X10, 0XE7, 0X11, 0X07, + 0X19, 0X27, 0X19, 0X28, 0X29, 0XA9, 0X31, 0XEB, 0X3A, 0X2C, 0X3A, 0X2E, + 0X29, 0XAC, 0X21, 0X09, 0X18, 0XC8, 0X18, 0XA7, 0X20, 0XE8, 0X29, 0X29, + 0X29, 0X29, 0X29, 0X29, 0X29, 0X29, 0X29, 0X29, 0X31, 0X4A, 0X29, 0X09, + 0X29, 0X29, 0X29, 0X29, 0X29, 0X29, 0X21, 0X49, 0X29, 0X6A, 0X29, 0X8B, + 0X29, 0X6A, 0X21, 0X4A, 0X21, 0X6A, 0X21, 0X08, 0X29, 0X29, 0X29, 0X6A, + 0X29, 0X49, 0X21, 0X07, 0X21, 0X48, 0X29, 0X08, 0X10, 0XE4, 0X10, 0XA3, + 0X10, 0XC4, 0X10, 0XA3, 0X10, 0XA3, 0X18, 0XE4, 0X21, 0X66, 0X19, 0X46, + 0X11, 0X26, 0X19, 0X25, 0X19, 0X66, 0X19, 0X25, 0X19, 0X46, 0X19, 0X67, + 0X11, 0X05, 0X19, 0X46, 0X19, 0X47, 0X19, 0X46, 0X21, 0X66, 0X19, 0X25, + 0X18, 0XE4, 0X31, 0X86, 0X31, 0X86, 0X31, 0X86, 0X41, 0XA7, 0X39, 0X66, + 0X29, 0X66, 0X29, 0X45, 0X29, 0X04, 0X31, 0X65, 0X31, 0X65, 0X31, 0X67, + 0X39, 0X87, 0X41, 0X87, 0X31, 0X45, 0X29, 0X25, 0X31, 0X45, 0X31, 0X45, + 0X31, 0X66, 0X39, 0X87, 0X41, 0X87, 0X29, 0X45, 0X21, 0X25, 0X19, 0X04, + 0X21, 0X05, 0X31, 0XA8, 0X21, 0X26, 0X21, 0X05, 0X31, 0XA7, 0X31, 0XC8, + 0X39, 0XE9, 0X39, 0XE9, 0X39, 0XC7, 0X29, 0XA8, 0X39, 0XA7, 0X29, 0X87, + 0X29, 0X66, 0X31, 0X86, 0X41, 0XC6, 0X41, 0XC7, 0X49, 0XE8, 0X41, 0XE9, + 0X41, 0XC7, 0X49, 0XE8, 0X4A, 0X29, 0X42, 0X09, 0X4A, 0X08, 0X4A, 0X29, + 0X31, 0X87, 0X39, 0XC8, 0X41, 0XC7, 0X31, 0XA7, 0X29, 0X66, 0X29, 0X87, + 0X29, 0XA7, 0X41, 0XC8, 0X41, 0XC7, 0X29, 0X66, 0X31, 0X65, 0X41, 0XC7, + 0X39, 0XA7, 0X39, 0XC7, 0X52, 0X07, 0X51, 0XE8, 0X49, 0XE7, 0X49, 0XE8, + 0X4A, 0X49, 0X52, 0X69, 0X4A, 0X28, 0X4A, 0X29, 0X52, 0X48, 0X5A, 0X89, + 0X4A, 0X08, 0X39, 0X45, 0X4A, 0X07, 0X52, 0X28, 0X5A, 0X8A, 0X4A, 0X29, + 0X29, 0X45, 0X39, 0XA7, 0X4A, 0X08, 0X4A, 0X08, 0X41, 0XE7, 0X41, 0XE8, + 0X41, 0XE8, 0X4A, 0X2A, 0X5A, 0XAA, 0X4A, 0X09, 0X41, 0XE8, 0X41, 0XE8, + 0X41, 0XE8, 0X41, 0XE8, 0X49, 0XE7, 0X4A, 0X09, 0X52, 0X6B, 0X52, 0X29, + 0X49, 0XE7, 0X51, 0XC7, 0X41, 0XA6, 0X31, 0X45, 0X31, 0X87, 0X39, 0XA6, + 0X39, 0X44, 0X31, 0X25, 0X31, 0X25, 0X31, 0X45, 0X31, 0X45, 0X41, 0XA6, + 0X5A, 0X6A, 0X6A, 0XCC, 0X52, 0X29, 0X49, 0XA7, 0X41, 0X86, 0X41, 0X66, + 0X31, 0X46, 0X31, 0X46, 0X41, 0X66, 0X31, 0X66, 0X52, 0X4A, 0X6A, 0XAB, + 0X5A, 0X08, 0X39, 0X66, 0X21, 0X47, 0X29, 0XA9, 0X29, 0XC9, 0X21, 0XCA, + 0X22, 0X0B, 0X21, 0XCA, 0X31, 0X46, 0X29, 0XA8, 0X42, 0X09, 0X31, 0X87, + 0X29, 0X46, 0X29, 0X47, 0X19, 0X46, 0X11, 0X27, 0X29, 0X88, 0X5A, 0X48, + 0X49, 0XE7, 0X31, 0XA8, 0X31, 0X87, 0X49, 0XC8, 0X39, 0XC9, 0X41, 0XE8, + 0X29, 0X66, 0X21, 0X45, 0X29, 0X67, 0X31, 0XA8, 0X29, 0X88, 0X29, 0X66, + 0X39, 0XE8, 0X5B, 0X0C, 0X4A, 0X49, 0X39, 0X86, 0X52, 0XA9, 0X4A, 0XAA, + 0X32, 0X29, 0X52, 0XAA, 0X52, 0XAA, 0X4A, 0X8A, 0X42, 0X69, 0X42, 0X6A, + 0X42, 0X6A, 0X52, 0XAB, 0X3A, 0X07, 0X3A, 0X27, 0X29, 0XE7, 0X19, 0X66, + 0X21, 0XC8, 0X21, 0XC7, 0X2A, 0X09, 0X29, 0XE9, 0X29, 0XC8, 0X53, 0X2C, + 0X73, 0XAC, 0X63, 0X09, 0X32, 0X29, 0X2A, 0X2A, 0X2A, 0X09, 0X32, 0X08, + 0X2A, 0X09, 0X32, 0X6B, 0X42, 0X6A, 0X32, 0X4A, 0X4A, 0XEC, 0XAC, 0X8B, + 0XA4, 0X4A, 0X5A, 0XEA, 0X32, 0X6A, 0X53, 0X0B, 0X32, 0X4A, 0X32, 0X4B, + 0X4A, 0X89, 0X42, 0XCE, 0X83, 0X49, 0XAB, 0XA5, 0XAB, 0X85, 0XB3, 0XA6, + 0XCB, 0XE5, 0XC4, 0X46, 0XAB, 0XA8, 0XAB, 0X87, 0XA3, 0XA7, 0X52, 0XEA, + 0X83, 0X26, 0XBB, 0XE5, 0XCC, 0X26, 0X7B, 0X07, 0X4A, 0X27, 0XEC, 0X45, + 0X59, 0X82, 0X00, 0X00, 0X10, 0XE5, 0X19, 0X47, 0X11, 0X26, 0X08, 0XC5, + 0X20, 0XE4, 0X31, 0X04, 0X30, 0XE4, 0X41, 0X03, 0X41, 0X43, 0X41, 0X64, + 0X41, 0X44, 0X31, 0X24, 0X41, 0X23, 0X41, 0X23, 0X41, 0X44, 0X39, 0X24, + 0X39, 0X25, 0X31, 0X25, 0X39, 0X46, 0X39, 0X25, 0X49, 0X24, 0X41, 0X65, + 0X41, 0X25, 0X39, 0X45, 0X31, 0X25, 0X39, 0X25, 0X31, 0X45, 0X41, 0X44, + 0X31, 0X24, 0X41, 0X45, 0X49, 0X66, 0X29, 0X46, 0X39, 0X46, 0X41, 0X67, + 0X29, 0X68, 0X29, 0X47, 0X29, 0X47, 0X29, 0X47, 0X29, 0X27, 0X31, 0X26, + 0X41, 0X66, 0X49, 0XC8, 0X41, 0X87, 0X29, 0X46, 0X29, 0X46, 0X29, 0X67, + 0X39, 0XA8, 0X49, 0X86, 0X49, 0X87, 0X41, 0XC9, 0X41, 0XA9, 0X39, 0X68, + 0X49, 0XC8, 0X5A, 0X08, 0X5A, 0X29, 0X41, 0XEA, 0X4A, 0X4B, 0X4A, 0X4A, + 0X4A, 0X08, 0X51, 0XA5, 0X52, 0X4A, 0X52, 0XAC, 0X52, 0X8B, 0X39, 0XCA, + 0X52, 0X8B, 0X52, 0X4A, 0X49, 0XA6, 0X41, 0X87, 0X41, 0X88, 0X41, 0X87, + 0X41, 0X67, 0X31, 0X25, 0X39, 0X45, 0X51, 0X85, 0X59, 0X85, 0X49, 0X87, + 0X49, 0XA8, 0X51, 0X86, 0X49, 0X66, 0X51, 0XA6, 0X49, 0XA6, 0X49, 0XA5, + 0X49, 0X86, 0X49, 0X85, 0X39, 0X24, 0X39, 0X45, 0X39, 0X46, 0X39, 0X45, + 0X41, 0X45, 0X51, 0X65, 0X51, 0X65, 0X49, 0X45, 0X49, 0XC8, 0X4A, 0X0B, + 0X49, 0XC9, 0X41, 0X66, 0X39, 0X45, 0X29, 0X46, 0X21, 0X27, 0X19, 0X28, + 0X19, 0X69, 0X21, 0X48, 0X21, 0X47, 0X29, 0X26, 0X19, 0X26, 0X08, 0XE6, + 0X08, 0XA4, 0X11, 0X26, 0X29, 0XA9, 0X11, 0X06, 0X19, 0X27, 0X19, 0X26, + 0X18, 0XE4, 0X21, 0X05, 0X21, 0X25, 0X21, 0X46, 0X21, 0X25, 0X21, 0X25, + 0X21, 0X25, 0X21, 0X05, 0X21, 0X46, 0X18, 0XE5, 0X18, 0XE4, 0X18, 0XE4, + 0X18, 0XE4, 0X21, 0X05, 0X21, 0X25, 0X21, 0X26, 0X21, 0X25, 0X21, 0X25, + 0X19, 0X06, 0X19, 0X27, 0X19, 0X47, 0X19, 0X47, 0X29, 0XC9, 0X29, 0XCA, + 0X29, 0XEA, 0X19, 0X47, 0X11, 0X26, 0X11, 0X06, 0X11, 0X06, 0X10, 0XE5, + 0X11, 0X06, 0X10, 0XE5, 0X19, 0X26, 0X31, 0XA8, 0X31, 0XA8, 0X21, 0X25, + 0X21, 0X25, 0X19, 0X05, 0X19, 0X05, 0X21, 0X25, 0X19, 0X04, 0X21, 0X05, + 0X21, 0X26, 0X19, 0X05, 0X21, 0X26, 0X18, 0XE5, 0X18, 0XE5, 0X18, 0XE4, + 0X11, 0X05, 0X10, 0XE5, 0X39, 0X25, 0X31, 0X86, 0X29, 0X25, 0X39, 0X45, + 0X30, 0XE4, 0X31, 0X04, 0X39, 0X24, 0X41, 0X24, 0X41, 0X44, 0X49, 0X85, + 0X41, 0X65, 0X41, 0X86, 0X41, 0X87, 0X31, 0X26, 0X41, 0X45, 0X41, 0X45, + 0X51, 0X85, 0X49, 0X66, 0X31, 0X05, 0X41, 0X45, 0X41, 0X44, 0X31, 0X03, + 0X41, 0X44, 0X41, 0X65, 0X41, 0X64, 0X51, 0X85, 0X61, 0XA5, 0X59, 0XA4, + 0X51, 0XA5, 0X61, 0XA5, 0X41, 0X85, 0X51, 0X85, 0X49, 0X64, 0X49, 0X85, + 0X51, 0XA6, 0X49, 0X85, 0X49, 0X86, 0X39, 0X25, 0X31, 0X05, 0X28, 0XC4, + 0X29, 0X67, 0X10, 0XC4, 0X00, 0X00, 0X00, 0X00, 0X40, 0XE3, 0X81, 0XC5, + 0X79, 0XA5, 0X69, 0XA5, 0X72, 0X26, 0X6A, 0X27, 0X9A, 0XC6, 0X7A, 0X46, + 0X51, 0XC7, 0X7A, 0X26, 0X7A, 0X67, 0X7A, 0X88, 0X92, 0XA7, 0XB2, 0XC6, + 0X59, 0XA5, 0X39, 0X45, 0X41, 0X65, 0X39, 0X45, 0X39, 0X45, 0X39, 0X65, + 0X41, 0X86, 0X41, 0X86, 0X41, 0X86, 0X41, 0X86, 0X41, 0X87, 0X49, 0X65, + 0X51, 0X85, 0X59, 0XC7, 0X5A, 0X0A, 0X59, 0XE9, 0X59, 0XC8, 0X51, 0XC9, + 0X59, 0X87, 0X59, 0X87, 0X69, 0XA6, 0X61, 0X86, 0X41, 0XC8, 0X41, 0X87, + 0X31, 0X46, 0X39, 0X88, 0X6A, 0X26, 0X82, 0X65, 0X7A, 0X45, 0X7A, 0X65, + 0X59, 0XC5, 0X39, 0X67, 0X41, 0XA7, 0X39, 0X86, 0X39, 0XC8, 0X08, 0X41, + 0X18, 0XA1, 0X62, 0X87, 0X5A, 0X46, 0X5A, 0X67, 0X62, 0XA7, 0X62, 0XA7, + 0X62, 0XA7, 0X62, 0X86, 0X62, 0XA6, 0X6A, 0XA6, 0X6A, 0XC6, 0X6A, 0XC7, + 0X5A, 0X45, 0X52, 0X47, 0X52, 0X67, 0X52, 0X68, 0X5A, 0XE8, 0X63, 0X48, + 0X63, 0X48, 0X52, 0XA7, 0X6B, 0X28, 0X7B, 0XA8, 0X7B, 0XA9, 0X7B, 0XA9, + 0X93, 0XE8, 0X83, 0XA8, 0X73, 0X69, 0X7B, 0X89, 0X6B, 0X29, 0X8B, 0XCA, + 0X9C, 0X2A, 0X9C, 0X2A, 0X94, 0X09, 0X83, 0X88, 0X83, 0X88, 0X83, 0XA9, + 0X83, 0XA9, 0X83, 0X88, 0X83, 0X68, 0X83, 0X88, 0X7B, 0X6B, 0X7B, 0X6A, + 0X8B, 0XC9, 0X94, 0X0B, 0X94, 0X0B, 0X8B, 0XCB, 0X93, 0XC9, 0X8B, 0XAA, + 0X83, 0X68, 0X7B, 0X47, 0X7B, 0X88, 0X72, 0XC8, 0X52, 0X26, 0X52, 0XE7, + 0X6B, 0X2A, 0X63, 0X2A, 0X6B, 0X29, 0X6B, 0X28, 0X41, 0XE6, 0X31, 0XA5, + 0X32, 0X29, 0X32, 0X8B, 0X32, 0X6A, 0X32, 0X6A, 0X32, 0X6A, 0X32, 0X6B, + 0X22, 0X4B, 0X2A, 0XAC, 0X32, 0XCC, 0X32, 0XAC, 0X43, 0X0E, 0X32, 0XAD, + 0X2A, 0X8D, 0X32, 0XAD, 0X3A, 0XCD, 0X3A, 0XED, 0X2A, 0XCC, 0X32, 0XEC, + 0X4B, 0X8E, 0X42, 0XCC, 0X42, 0XAB, 0X32, 0X6A, 0X32, 0X6A, 0X43, 0X0C, + 0X43, 0X4E, 0X3B, 0X0E, 0X32, 0X8B, 0X32, 0XAC, 0X32, 0XEE, 0X32, 0XCD, + 0X32, 0XCC, 0X32, 0XCC, 0X2A, 0XCD, 0X2B, 0X0E, 0X2B, 0X0E, 0X3B, 0X6F, + 0X33, 0X2E, 0X33, 0X0E, 0X3A, 0XCE, 0X32, 0X6C, 0X3A, 0X6A, 0X42, 0XAB, + 0X43, 0X2D, 0X43, 0X2D, 0X43, 0X6E, 0X4B, 0X6F, 0X4B, 0X2D, 0X3A, 0X8A, + 0X42, 0X8A, 0X4A, 0XCB, 0X4A, 0XCB, 0X42, 0X89, 0X53, 0XCF, 0X54, 0X71, + 0X54, 0X2F, 0X4C, 0X0F, 0X3B, 0X4D, 0X3B, 0X4D, 0X3B, 0X0C, 0X3B, 0X2D, + 0X3A, 0XEC, 0X22, 0X08, 0X33, 0X11, 0X43, 0XD8, 0X43, 0XB7, 0X3B, 0X33, + 0X3A, 0XEA, 0X53, 0XAD, 0X3B, 0X4D, 0X33, 0X4D, 0X32, 0X29, 0X21, 0XC8, + 0X32, 0X4A, 0X32, 0X4A, 0X2A, 0X49, 0X11, 0X65, 0X08, 0XA2, 0X08, 0XC3, + 0X11, 0X66, 0X22, 0X68, 0X33, 0X6B, 0X3B, 0XAB, 0X19, 0XE7, 0X08, 0XC3, + 0X08, 0X61, 0X29, 0XE9, 0X32, 0X2B, 0X31, 0XC8, 0X3A, 0X29, 0X42, 0X6B, + 0X32, 0X09, 0X29, 0XC8, 0X29, 0XE8, 0X32, 0X8A, 0X32, 0X6A, 0X1A, 0X09, + 0X32, 0XAB, 0X32, 0XCC, 0X32, 0XAD, 0X2A, 0X4A, 0X21, 0XC8, 0X19, 0XC8, + 0X19, 0XC8, 0X19, 0XA6, 0X22, 0X09, 0X22, 0X09, 0X22, 0X2A, 0X22, 0X2A, + 0X12, 0X09, 0X1A, 0X2C, 0X21, 0XEB, 0X19, 0XCA, 0X22, 0X4D, 0X1A, 0XAE, + 0X22, 0X2A, 0X2A, 0X2B, 0X2A, 0X6C, 0X22, 0X09, 0X2A, 0X4A, 0X2A, 0X6A, + 0X32, 0X29, 0X2A, 0X08, 0X2A, 0X49, 0X2A, 0X49, 0X2A, 0X89, 0X2A, 0X8A, + 0X2A, 0X4A, 0X22, 0X09, 0X21, 0XC7, 0X21, 0XC9, 0X21, 0XC9, 0X22, 0X0A, + 0X22, 0X2A, 0X21, 0XA8, 0X21, 0XE9, 0X29, 0X86, 0X29, 0XE8, 0X22, 0X29, + 0X22, 0X4A, 0X2A, 0X49, 0X21, 0XA7, 0X32, 0X4A, 0X32, 0X4A, 0X21, 0XC8, + 0X19, 0X65, 0X31, 0XA6, 0X2A, 0X6A, 0X2A, 0X0A, 0X2A, 0X6A, 0X32, 0X09, + 0X2A, 0X49, 0X2A, 0X2A, 0X22, 0X4B, 0X2A, 0X4B, 0X6B, 0X2C, 0X83, 0X8A, + 0X73, 0X2B, 0X73, 0X4C, 0X6A, 0XEA, 0X6B, 0X4F, 0X73, 0X8F, 0X53, 0X0C, + 0X3A, 0XAA, 0X53, 0XB0, 0X5B, 0XB2, 0X63, 0X70, 0X5B, 0X90, 0X2A, 0XCD, + 0X32, 0XAC, 0X32, 0X8B, 0X22, 0X8B, 0X2A, 0X48, 0X22, 0X6A, 0X7C, 0X70, + 0XA4, 0X4D, 0X63, 0XCD, 0X4B, 0XD0, 0X4B, 0XAF, 0X74, 0X0F, 0X5B, 0X4D, + 0X4A, 0XAA, 0X42, 0XA9, 0X63, 0X2A, 0X63, 0X2A, 0X4A, 0XA9, 0X32, 0X06, + 0X4A, 0X8A, 0X42, 0X48, 0X3A, 0X27, 0X42, 0X27, 0X42, 0X68, 0X4A, 0XAA, + 0X42, 0X89, 0X3A, 0XAA, 0X3A, 0XAA, 0X3A, 0XCA, 0X3A, 0XA9, 0X3A, 0X49, + 0X4A, 0XEA, 0X43, 0X29, 0X42, 0XEB, 0X4B, 0X4B, 0X43, 0X6A, 0X43, 0X2B, + 0X43, 0X0B, 0X5B, 0XEC, 0X5B, 0XAD, 0X5B, 0XAD, 0X53, 0X8C, 0X4B, 0X8B, + 0X4B, 0X4A, 0X4A, 0XA9, 0X4A, 0X8B, 0X39, 0XC8, 0X39, 0XA8, 0X41, 0XE7, + 0X4A, 0X07, 0X41, 0XE9, 0X4A, 0X07, 0X52, 0X49, 0X5A, 0X6A, 0X4A, 0X08, + 0X39, 0XA8, 0X31, 0X86, 0X31, 0X65, 0X18, 0XA2, 0X08, 0X41, 0X29, 0X65, + 0X29, 0X65, 0X31, 0X65, 0X31, 0X85, 0X29, 0X24, 0X21, 0X04, 0X21, 0X04, + 0X29, 0X66, 0X29, 0X86, 0X29, 0X66, 0X21, 0X25, 0X31, 0X86, 0X31, 0XA9, + 0X31, 0XA8, 0X29, 0X44, 0X29, 0X66, 0X29, 0X66, 0X29, 0X46, 0X31, 0X87, + 0X31, 0X66, 0X29, 0X66, 0X31, 0XA7, 0X31, 0X86, 0X31, 0X86, 0X31, 0X86, + 0X29, 0X66, 0X29, 0X46, 0X21, 0X25, 0X29, 0X45, 0X21, 0X26, 0X29, 0X46, + 0X31, 0XA8, 0X31, 0X87, 0X31, 0X87, 0X31, 0XA7, 0X31, 0X67, 0X31, 0XA8, + 0X31, 0X87, 0X31, 0XA8, 0X32, 0X0A, 0X31, 0XA7, 0X31, 0X87, 0X31, 0XC8, + 0X39, 0XC8, 0X31, 0X86, 0X29, 0X45, 0X42, 0X29, 0X39, 0XC7, 0X31, 0X86, + 0X31, 0X65, 0X10, 0X82, 0X00, 0X00, 0X21, 0X86, 0X32, 0X69, 0X32, 0X69, + 0X3A, 0XCA, 0X43, 0X6C, 0X4B, 0XCF, 0X54, 0XF8, 0X54, 0XF8, 0X5C, 0XF6, + 0X5C, 0X92, 0X64, 0XD6, 0X64, 0XF3, 0X5D, 0X37, 0X54, 0XB7, 0X5C, 0XB6, + 0X54, 0X96, 0X54, 0X96, 0X54, 0X95, 0X54, 0X75, 0X64, 0XD6, 0X54, 0X75, + 0X64, 0X34, 0X6C, 0XD8, 0X4B, 0X90, 0X42, 0X47, 0X6C, 0X95, 0X6D, 0X58, + 0X44, 0X12, 0X33, 0X2B, 0X43, 0XEE, 0X4C, 0X2F, 0X5B, 0X8D, 0X4C, 0X11, + 0X5C, 0X0F, 0X64, 0X0F, 0X5B, 0XEE, 0X64, 0X0E, 0X6C, 0XB3, 0X64, 0XF6, + 0X5C, 0XB6, 0X4B, 0XF1, 0X53, 0XF0, 0X5C, 0X10, 0X6C, 0X94, 0X6C, 0X52, + 0X6B, 0XD0, 0X64, 0X72, 0X5C, 0X53, 0X63, 0XF2, 0X5B, 0XF1, 0X43, 0XAC, + 0X4C, 0X50, 0X63, 0XEF, 0X6B, 0XEF, 0X6C, 0X11, 0X6B, 0XEF, 0X5C, 0X30, + 0X64, 0X30, 0X64, 0X0F, 0X6C, 0X30, 0X53, 0X91, 0X4B, 0X92, 0X4B, 0X0D, + 0X3B, 0X0B, 0X5C, 0X11, 0X64, 0X31, 0X64, 0X12, 0X63, 0XF1, 0X63, 0XF1, + 0X5C, 0X11, 0X6B, 0X2D, 0X63, 0X0B, 0X53, 0X6D, 0X53, 0X2B, 0X5C, 0XB4, + 0X5C, 0X71, 0X64, 0X70, 0X6C, 0X0F, 0X64, 0X72, 0X64, 0X31, 0X6B, 0X6C, + 0X4B, 0X4C, 0X43, 0X2B, 0X4B, 0X6C, 0X53, 0X6C, 0X5B, 0X4C, 0X63, 0XAE, + 0X53, 0XEF, 0X4B, 0XED, 0X4B, 0X8D, 0X5C, 0X31, 0X54, 0X6F, 0X65, 0X76, + 0X65, 0X78, 0X65, 0X54, 0X65, 0X97, 0X65, 0X78, 0X65, 0X79, 0X65, 0X16, + 0X53, 0XCD, 0X53, 0XAC, 0X43, 0X2B, 0X4C, 0X32, 0X4C, 0XB4, 0X4B, 0XEF, + 0X4B, 0X8B, 0X53, 0X07, 0X53, 0X49, 0X5C, 0X0F, 0X64, 0XB2, 0X6C, 0XB4, + 0X6C, 0XD2, 0X4B, 0X6E, 0X5C, 0X12, 0X64, 0X32, 0X4A, 0XEA, 0X4A, 0XA9, + 0X53, 0X4B, 0X75, 0X34, 0X74, 0XF5, 0X53, 0X6B, 0X4A, 0XC9, 0X53, 0XEF, + 0X54, 0X10, 0X5C, 0X4F, 0X74, 0X8C, 0X53, 0X8A, 0X64, 0X4D, 0X64, 0X8E, + 0X64, 0X2D, 0X63, 0XEC, 0X64, 0X0D, 0X64, 0X0D, 0X63, 0XED, 0X5B, 0XCC, + 0X63, 0XEC, 0X5B, 0XAC, 0X5B, 0XEE, 0X63, 0XEF, 0X6C, 0X2D, 0X6C, 0X4C, + 0X6C, 0X6D, 0X6C, 0X0E, 0X6B, 0XEE, 0X6C, 0X0E, 0X6C, 0X0E, 0X6C, 0X4E, + 0X74, 0XEE, 0X64, 0X6E, 0X64, 0X2F, 0X64, 0X2E, 0X5C, 0X0D, 0X5C, 0X0C, + 0X5C, 0X0E, 0X6C, 0X4D, 0X5B, 0XCC, 0X6B, 0XEB, 0X53, 0X4B, 0X63, 0XAB, + 0X6B, 0XCC, 0X63, 0X4A, 0X5B, 0X8A, 0X54, 0X4F, 0X64, 0X91, 0X64, 0XD1, + 0X5B, 0XCB, 0X5B, 0XCD, 0X5C, 0X2F, 0X53, 0XCC, 0X5B, 0XAD, 0X53, 0X09, + 0X4A, 0XE9, 0X5B, 0X8C, 0X08, 0XE6, 0X08, 0XC5, 0X08, 0XA4, 0X08, 0XC5, + 0X08, 0XE6, 0X00, 0XA4, 0X09, 0X06, 0X09, 0X06, 0X09, 0X06, 0X08, 0XC5, + 0X08, 0XE5, 0X10, 0XC4, 0X11, 0X26, 0X11, 0X89, 0X09, 0X27, 0X08, 0XE5, + 0X08, 0XE5, 0X09, 0X27, 0X09, 0X27, 0X09, 0X47, 0X09, 0X48, 0X08, 0XE6, + 0X11, 0X27, 0X08, 0XE5, 0X08, 0XC4, 0X08, 0XC4, 0X11, 0X26, 0X11, 0X06, + 0X08, 0XE7, 0X08, 0XC5, 0X08, 0XC5, 0X08, 0XC5, 0X08, 0XC5, 0X08, 0XC5, + 0X08, 0XC5, 0X08, 0XE6, 0X09, 0X07, 0X08, 0XC5, 0X10, 0XE5, 0X08, 0XC5, + 0X08, 0XA5, 0X08, 0XC5, 0X11, 0X28, 0X11, 0X28, 0X11, 0X07, 0X11, 0X06, + 0X11, 0X07, 0X11, 0X07, 0X11, 0X07, 0X11, 0X26, 0X11, 0X06, 0X11, 0X07, + 0X11, 0X07, 0X11, 0X07, 0X11, 0X07, 0X11, 0X06, 0X10, 0XE6, 0X10, 0XE6, + 0X10, 0XE6, 0X10, 0XE6, 0X11, 0X07, 0X11, 0X07, 0X11, 0X07, 0X09, 0X08, + 0X09, 0X29, 0X08, 0XE7, 0X08, 0XE6, 0X09, 0X08, 0X09, 0X28, 0X11, 0X48, + 0X11, 0X27, 0X10, 0XE6, 0X11, 0X07, 0X11, 0X06, 0X11, 0X05, 0X11, 0X07, + 0X11, 0X07, 0X11, 0X07, 0X10, 0XE7, 0X10, 0XE6, 0X11, 0X07, 0X10, 0XE7, + 0X10, 0XE6, 0X11, 0X07, 0X11, 0X28, 0X08, 0XE6, 0X09, 0X09, 0X09, 0X08, + 0X09, 0X09, 0X09, 0X09, 0X09, 0X2A, 0X08, 0XE8, 0X08, 0XE8, 0X09, 0X09, + 0X09, 0X29, 0X09, 0X29, 0X09, 0X2A, 0X08, 0XC7, 0X08, 0XC7, 0X08, 0XE8, + 0X09, 0X09, 0X08, 0XC7, 0X08, 0XC5, 0X00, 0XC8, 0X08, 0XC8, 0X08, 0XC7, + 0X11, 0X07, 0X11, 0X27, 0X11, 0X06, 0X08, 0XC5, 0X08, 0XC6, 0X08, 0XC6, + 0X08, 0XA5, 0X10, 0XC4, 0X10, 0XC5, 0X10, 0XE6, 0X10, 0XC6, 0X08, 0XE7, + 0X08, 0XE9, 0X08, 0XE9, 0X09, 0X09, 0X08, 0XE7, 0X08, 0XE8, 0X08, 0XE8, + 0X08, 0X84, 0X08, 0X84, 0X00, 0XA6, 0X00, 0XC7, 0X00, 0XC7, 0X08, 0XE8, + 0X08, 0XE8, 0X09, 0X08, 0X08, 0XE8, 0X00, 0X63, 0X00, 0X00, 0X00, 0X00, + 0X08, 0X41, 0X5A, 0XCD, 0X6B, 0X2E, 0X63, 0X0C, 0X5A, 0XAB, 0X52, 0X8A, + 0X5A, 0XAC, 0X52, 0X6B, 0X52, 0X6A, 0X52, 0X6B, 0X4A, 0X6B, 0X52, 0X8C, + 0X63, 0X2E, 0X63, 0X2B, 0X73, 0X6D, 0X5A, 0XCB, 0X63, 0X4D, 0X63, 0X6D, + 0X63, 0X2C, 0X6B, 0X4D, 0X63, 0X0C, 0X52, 0XA9, 0X6B, 0X06, 0X5A, 0X86, + 0X41, 0XE4, 0X62, 0XC6, 0X72, 0XE8, 0X6A, 0XA8, 0X6A, 0XA8, 0X6A, 0XC8, + 0X6A, 0XA8, 0X6A, 0XA9, 0X6A, 0XC9, 0X72, 0XEA, 0X7B, 0X2B, 0X7B, 0X2B, + 0X73, 0X0A, 0X73, 0X0A, 0X62, 0XA9, 0X62, 0X88, 0X62, 0X89, 0X62, 0X69, + 0X62, 0XA9, 0X6B, 0X0A, 0X6A, 0XEA, 0X72, 0XE9, 0X7B, 0X29, 0X72, 0XE9, + 0X6A, 0XA9, 0X6A, 0XC9, 0X62, 0X89, 0X5A, 0X69, 0X5A, 0X69, 0X5A, 0X48, + 0X5A, 0X8A, 0X5A, 0XAA, 0X4A, 0X07, 0X5A, 0XAA, 0X5A, 0XAA, 0X5A, 0XA9, + 0X5A, 0XA9, 0X52, 0X68, 0X52, 0X48, 0X5A, 0X69, 0X49, 0XE6, 0X49, 0XC6, + 0X4A, 0X07, 0X5A, 0X8A, 0X62, 0XCA, 0X7B, 0X4C, 0X73, 0X4C, 0X5A, 0XAA, + 0X5A, 0X89, 0X62, 0XEB, 0X62, 0XEB, 0X5A, 0XCA, 0X52, 0XAA, 0X52, 0X68, + 0X4A, 0X47, 0X52, 0X88, 0X6B, 0X6E, 0X6B, 0X4D, 0X62, 0XEB, 0X6B, 0X2C, + 0X6B, 0X2C, 0X6B, 0X2C, 0X6B, 0X4D, 0X73, 0X4D, 0X6B, 0X4D, 0X73, 0X6D, + 0X73, 0X6D, 0X73, 0X6D, 0X73, 0X4D, 0X73, 0X4D, 0X73, 0X6E, 0X73, 0X6E, + 0X83, 0XAF, 0X83, 0XD0, 0X83, 0XD0, 0X83, 0XCF, 0X83, 0X8E, 0X7B, 0X6E, + 0X7B, 0X6E, 0X83, 0XAE, 0X83, 0X8E, 0X62, 0X8A, 0X6B, 0X0C, 0X52, 0X27, + 0X52, 0X27, 0X5A, 0X28, 0X5A, 0X68, 0X62, 0XEC, 0X7B, 0X6E, 0X73, 0X2C, + 0X62, 0XCB, 0X62, 0XCB, 0X62, 0XCB, 0X52, 0X8A, 0X5A, 0XE9, 0X73, 0X6C, + 0X73, 0X4E, 0X7B, 0XAF, 0X7B, 0XF0, 0X7B, 0XAF, 0X73, 0X4D, 0X7B, 0X8E, + 0X7B, 0X8E, 0X7B, 0X6E, 0X7B, 0XAE, 0X62, 0XEB, 0X62, 0XCA, 0X6A, 0XEB, + 0X5A, 0XAA, 0X4A, 0X29, 0X4A, 0X08, 0X4A, 0X28, 0X52, 0X49, 0X52, 0X6A, + 0X52, 0X4A, 0X4A, 0X08, 0X5A, 0XAB, 0X6B, 0X0D, 0X5A, 0X8A, 0X5A, 0X8A, + 0X62, 0X8A, 0X6A, 0XEA, 0X62, 0XA9, 0X41, 0XE6, 0X4A, 0X47, 0X6B, 0X2A, + 0X62, 0XCA, 0X73, 0X6E, 0X6B, 0X0C, 0X5A, 0X89, 0X4A, 0X28, 0X49, 0XE7, + 0X39, 0X85, 0X5A, 0XCA, 0X52, 0X48, 0X4A, 0X27, 0X5A, 0XA9, 0X73, 0X6D, + 0X63, 0X0C, 0X73, 0X8D, 0X7C, 0X0F, 0X6B, 0X0A, 0X42, 0X66, 0X4A, 0XA7, + 0X4A, 0X65, 0X42, 0X86, 0X3A, 0X69, 0X3A, 0X28, 0X32, 0X27, 0X4A, 0XC8, + 0X42, 0X89, 0X29, 0XA6, 0X4A, 0XA7, 0X5B, 0X28, 0X52, 0X88, 0X5B, 0X28, + 0X5B, 0X6A, 0X4B, 0X0E, 0X4B, 0X0D, 0X4B, 0X0D, 0X4A, 0XEC, 0X5B, 0X6A, + 0X53, 0X49, 0X6B, 0X8B, 0X6B, 0X49, 0X6B, 0X69, 0X62, 0XC6, 0X62, 0XE7, + 0X6A, 0XE8, 0X73, 0X09, 0X72, 0XEA, 0X73, 0X0A, 0X6B, 0X0A, 0X6B, 0X2A, + 0X73, 0X69, 0X63, 0X07, 0X6B, 0X4A, 0X6B, 0X4B, 0X63, 0X29, 0X63, 0X29, + 0X63, 0X29, 0X5B, 0X08, 0X4A, 0XC7, 0X4A, 0X88, 0X83, 0X8D, 0X5A, 0XC9, + 0X29, 0XC5, 0X31, 0XE5, 0X29, 0XC5, 0X31, 0XC4, 0X00, 0X61, 0X08, 0XC2, + 0X42, 0X46, 0X5A, 0XE9, 0X6B, 0X4A, 0X6B, 0X6A, 0X63, 0X29, 0X5B, 0X6C, + 0X5B, 0XCD, 0X4A, 0XC7, 0X4A, 0XA7, 0X4A, 0XC7, 0X4A, 0XA7, 0X4A, 0XA7, + 0X5B, 0X6B, 0X63, 0XCE, 0X63, 0XCE, 0X5B, 0X29, 0X53, 0X08, 0X4A, 0XE8, + 0X4A, 0XE8, 0X4A, 0XE8, 0X3A, 0XC8, 0X4B, 0X08, 0X42, 0XE8, 0X5B, 0X28, + 0X63, 0X29, 0X6B, 0X49, 0X6B, 0X69, 0X7B, 0XAA, 0X6B, 0X28, 0X52, 0XA7, + 0X6B, 0X48, 0X73, 0X8A, 0X7B, 0XC9, 0X84, 0X0A, 0X73, 0XA9, 0X5A, 0XE7, + 0X5B, 0X28, 0X6B, 0X6B, 0X6B, 0X6A, 0X7B, 0XCB, 0X63, 0X69, 0X5B, 0X69, + 0X5B, 0X89, 0X5B, 0X49, 0X7B, 0X8B, 0X63, 0X2A, 0X63, 0X8D, 0X63, 0X4D, + 0X52, 0XAA, 0X52, 0XA9, 0X5A, 0XE9, 0X63, 0X0A, 0X6B, 0X4A, 0X7C, 0X0C, + 0X6B, 0X4A, 0X5B, 0X08, 0X63, 0X4C, 0X6B, 0XAD, 0X73, 0XEC, 0X63, 0X2C, + 0X73, 0XAC, 0X73, 0X6A, 0X63, 0X4A, 0X6B, 0X6B, 0X63, 0X29, 0X73, 0X49, + 0X73, 0XCA, 0X5B, 0X49, 0X6B, 0X4A, 0X6B, 0X2A, 0X6B, 0X4A, 0X6B, 0X4A, + 0X6B, 0X4A, 0X6B, 0X4A, 0X63, 0X69, 0X5B, 0X08, 0X42, 0X05, 0X52, 0X88, + 0X62, 0XE8, 0X5A, 0X87, 0X5A, 0XA7, 0X63, 0X07, 0X63, 0X09, 0X52, 0XAA, + 0X5A, 0X87, 0X6A, 0XE7, 0X62, 0XC7, 0X6B, 0X08, 0X7B, 0XCB, 0X7C, 0X2B, + 0X73, 0XEB, 0X73, 0XEB, 0X6B, 0XAA, 0X63, 0X69, 0X63, 0X6A, 0X73, 0XEB, + 0X7C, 0X2B, 0X74, 0X2B, 0X74, 0X0B, 0X73, 0XEA, 0X5B, 0X08, 0X63, 0X29, + 0X73, 0XCB, 0X6B, 0XAA, 0X6B, 0XAA, 0X6B, 0XAA, 0X63, 0X49, 0X52, 0XE8, + 0X5B, 0X28, 0X5B, 0X28, 0X73, 0XC9, 0X7B, 0XEC, 0X5B, 0X08, 0X53, 0X07, + 0X53, 0XAA, 0X6C, 0X2C, 0X7C, 0X2B, 0X5B, 0X07, 0X52, 0XA6, 0X52, 0XC7, + 0X52, 0X67, 0X52, 0X46, 0X49, 0XE5, 0X52, 0XA8, 0X4A, 0X26, 0X5B, 0X0A, + 0X5A, 0XA8, 0X73, 0X06, 0X7B, 0X67, 0X63, 0X26, 0X6B, 0X46, 0X63, 0X26, + 0X63, 0X26, 0X6B, 0X46, 0X6B, 0X46, 0X6B, 0XA9, 0X6B, 0X68, 0X6B, 0X68, + 0X5B, 0X28, 0X63, 0X48, 0X52, 0XE7, 0X53, 0X07, 0X63, 0X69, 0X5B, 0X49, + 0X53, 0X48, 0X53, 0X28, 0X5B, 0XCA, 0X5B, 0X27, 0X5B, 0XAA, 0X5B, 0XAA, + 0X5B, 0X8A, 0X4B, 0X08, 0X4A, 0XC7, 0X53, 0X08, 0X63, 0X68, 0X53, 0X69, + 0X4B, 0X69, 0X53, 0X69, 0X63, 0XA9, 0X6C, 0X4A, 0X6C, 0X4A, 0X7C, 0X48, + 0X6C, 0X09, 0X6B, 0XE9, 0X6C, 0X09, 0X6B, 0X88, 0X63, 0X07, 0X5B, 0X87, + 0X63, 0XA7, 0X63, 0X87, 0X63, 0XA7, 0X73, 0XE9, 0X8C, 0X8C, 0X52, 0XE7, + 0X39, 0XE4, 0X52, 0XC6, 0X42, 0X05, 0X41, 0XC5, 0X49, 0XE5, 0X52, 0X46, + 0X53, 0X09, 0X5B, 0X8C, 0X53, 0X4B, 0X52, 0XEB, 0X52, 0XEB, 0X4A, 0XAB, + 0X4A, 0XEC, 0X53, 0X2E, 0X53, 0X0C, 0X5B, 0X29, 0X63, 0XEC, 0X64, 0X0C, + 0X74, 0X2F, 0X7C, 0X31, 0X6B, 0XCF, 0X52, 0XEB, 0X5A, 0XEA, 0X73, 0XED, + 0X6B, 0X4B, 0X62, 0XCA, 0X6B, 0X0B, 0X7B, 0XAD, 0X6B, 0X6C, 0X63, 0X2C, + 0X5B, 0X2D, 0X52, 0XEC, 0X52, 0XC8, 0X4A, 0X87, 0X73, 0X89, 0X7B, 0XAB, + 0X52, 0XEB, 0X52, 0XC9, 0X42, 0X08, 0X29, 0X25, 0X29, 0X65, 0X4A, 0X8A, + 0X5B, 0X0B, 0X4A, 0XCB, 0X3A, 0X6A, 0X4A, 0XA8, 0X2A, 0X4A, 0X29, 0XE9, + 0X43, 0X0A, 0X6C, 0X4B, 0X63, 0XEB, 0X5B, 0X4C, 0X42, 0X8A, 0X3A, 0X48, + 0X5B, 0X69, 0X5B, 0X6D, 0X3A, 0X8B, 0X29, 0XE9, 0X4B, 0X0C, 0X6C, 0X51, + 0X6B, 0XAC, 0X6B, 0X29, 0X6B, 0XCC, 0X73, 0XCC, 0X6B, 0X2A, 0X6B, 0X4A, + 0X73, 0XCB, 0X84, 0X6D, 0X7B, 0XAC, 0X63, 0X49, 0X63, 0X49, 0X73, 0XEB, + 0X73, 0X89, 0X63, 0X29, 0X7B, 0XEA, 0X7C, 0X2B, 0X7C, 0X4B, 0X83, 0XAC, + 0X73, 0X6A, 0X7B, 0XEB, 0X8D, 0X13, 0X8C, 0X91, 0X7B, 0X6B, 0X9C, 0X92, + 0X8C, 0X51, 0X7C, 0X10, 0X5B, 0X2D, 0X6A, 0XCA, 0X62, 0X48, 0X7C, 0X10, + 0X7C, 0X0F, 0X5A, 0X89, 0X83, 0X6C, 0X83, 0X6D, 0X73, 0X0A, 0X6B, 0X2B, + 0X52, 0XC9, 0X73, 0XCD, 0X74, 0X32, 0X74, 0X33, 0X6B, 0XD0, 0X5B, 0X2D, + 0X5B, 0X2D, 0X63, 0X8F, 0X74, 0X31, 0X74, 0X10, 0X84, 0X73, 0X84, 0X73, + 0X7C, 0XB3, 0X7C, 0XB3, 0X74, 0X53, 0X74, 0X74, 0X5A, 0XCB, 0X5A, 0X47, + 0X6A, 0XC9, 0X7A, 0XE9, 0X7B, 0X09, 0X7B, 0X4B, 0X7B, 0X6B, 0X7A, 0XEA, + 0X72, 0XEA, 0X72, 0XC9, 0X73, 0X6E, 0X73, 0XF0, 0X7B, 0XAA, 0X7B, 0X49, + 0X7A, 0XE9, 0X7B, 0X0A, 0X7C, 0X0D, 0X8B, 0XCD, 0X8B, 0XAC, 0X83, 0X6C, + 0X7A, 0XCA, 0X72, 0X89, 0X72, 0XAA, 0X6A, 0X88, 0X6A, 0XA9, 0X72, 0XA9, + 0X72, 0X89, 0X6A, 0XA8, 0X6A, 0XE9, 0X7B, 0X2A, 0X62, 0X88, 0X62, 0X67, + 0X7B, 0X4A, 0X7B, 0X0B, 0X6A, 0XC8, 0X6A, 0XC8, 0X6A, 0XC9, 0X7A, 0XA9, + 0X72, 0XEA, 0X72, 0XE9, 0X72, 0XC9, 0X72, 0XA9, 0X72, 0XA9, 0X7A, 0XEA, + 0X6A, 0XCA, 0X72, 0XA9, 0X7A, 0XA9, 0X7A, 0XC9, 0X6A, 0XA9, 0X73, 0X0A, + 0X72, 0XEA, 0X6A, 0X68, 0X73, 0X0A, 0X83, 0X4A, 0X8B, 0X8A, 0X8B, 0X6A, + 0X93, 0X8A, 0X8B, 0XAB, 0X93, 0XCB, 0X8B, 0X4A, 0X8B, 0X29, 0X93, 0XEC, + 0X93, 0X8A, 0X73, 0X69, 0X53, 0X6A, 0X7B, 0X6A, 0X6B, 0XAA, 0X73, 0X6A, + 0X63, 0X6D, 0X5B, 0XB0, 0X53, 0X4D, 0X63, 0XD1, 0X64, 0X12, 0X63, 0XAD, + 0X6B, 0XCC, 0X6B, 0XCC, 0X6B, 0X4A, 0X72, 0XE9, 0X83, 0X6C, 0X83, 0X4B, + 0X7A, 0X88, 0X72, 0X07, 0X7A, 0X27, 0X7A, 0X88, 0X7A, 0XEA, 0X72, 0XC9, + 0X7A, 0XC9, 0X6B, 0X0A, 0X62, 0XA8, 0X52, 0X26, 0X62, 0XC8, 0X73, 0X0A, + 0X62, 0XA9, 0X5A, 0X67, 0X52, 0X48, 0X4A, 0X28, 0X52, 0X48, 0X52, 0X69, + 0X5A, 0X69, 0X62, 0XCA, 0X52, 0X48, 0X4A, 0X48, 0X4A, 0X28, 0X4A, 0X48, + 0X4A, 0X89, 0X52, 0XA9, 0X5A, 0XA9, 0X4A, 0X06, 0X4A, 0X06, 0X62, 0X88, + 0X72, 0XE9, 0X73, 0X0A, 0X72, 0XC9, 0X6A, 0XA8, 0X6A, 0XE9, 0X73, 0X0B, + 0X6A, 0XA8, 0X6A, 0X47, 0X62, 0XE9, 0X6A, 0XE8, 0X6A, 0XE8, 0X6A, 0XE8, + 0X62, 0XC8, 0X6A, 0XA8, 0X7B, 0X2B, 0X73, 0X09, 0X72, 0XE9, 0X72, 0XE9, + 0X7B, 0X09, 0X7B, 0X69, 0X62, 0XE8, 0X6B, 0X0A, 0X6B, 0X0A, 0X73, 0X2A, + 0X62, 0X68, 0X62, 0X88, 0X7B, 0X29, 0X6A, 0X67, 0X6A, 0X87, 0X83, 0X29, + 0X6A, 0XA8, 0X5A, 0X67, 0X5A, 0X47, 0X6A, 0XC9, 0X6A, 0XEA, 0X6A, 0XEA, + 0X7B, 0X09, 0X73, 0X29, 0X72, 0XE9, 0X7B, 0X2A, 0X83, 0X2A, 0X83, 0X4A, + 0X83, 0X8B, 0X83, 0X8A, 0X6B, 0X08, 0X6B, 0X6A, 0X6B, 0X0A, 0X6A, 0XE9, + 0X73, 0X49, 0X6B, 0X6A, 0X5A, 0XA7, 0X4A, 0X26, 0X52, 0X67, 0X42, 0X26, + 0X31, 0XA5, 0X52, 0X47, 0X4A, 0X6B, 0X5B, 0X50, 0X6B, 0X6C, 0X73, 0X8D, + 0X62, 0XEA, 0X5B, 0X0E, 0X5B, 0X0D, 0X5B, 0X0B, 0X6B, 0X4D, 0X63, 0X0B, + 0X52, 0XC8, 0X5A, 0XE9, 0X63, 0X49, 0X19, 0X03, 0X00, 0X00, 0X00, 0X41, + 0X10, 0XE5, 0X11, 0X06, 0X19, 0X27, 0X19, 0X27, 0X19, 0X48, 0X11, 0X06, + 0X08, 0XA4, 0X08, 0XA4, 0X08, 0XC4, 0X11, 0X07, 0X11, 0X27, 0X08, 0XE7, + 0X10, 0XE6, 0X10, 0XE5, 0X19, 0X67, 0X21, 0X87, 0X19, 0X88, 0X11, 0X49, + 0X11, 0X29, 0X19, 0X69, 0X11, 0X49, 0X11, 0X29, 0X19, 0X67, 0X19, 0X87, + 0X19, 0X67, 0X11, 0X07, 0X11, 0X27, 0X11, 0X47, 0X19, 0X67, 0X19, 0X66, + 0X19, 0X87, 0X21, 0X87, 0X19, 0X67, 0X19, 0X66, 0X19, 0X45, 0X10, 0XC4, + 0X10, 0XC5, 0X11, 0X06, 0X11, 0X06, 0X11, 0X06, 0X11, 0X06, 0X10, 0XE6, + 0X11, 0X06, 0X11, 0X06, 0X10, 0XE6, 0X11, 0X06, 0X10, 0XE6, 0X08, 0XC5, + 0X11, 0X06, 0X19, 0X69, 0X19, 0X48, 0X19, 0X48, 0X19, 0X48, 0X11, 0X48, + 0X11, 0X28, 0X11, 0X28, 0X11, 0X06, 0X10, 0XC5, 0X08, 0XE6, 0X08, 0XC6, + 0X08, 0XC5, 0X08, 0XC5, 0X08, 0XC6, 0X08, 0XA5, 0X08, 0XC5, 0X08, 0XE6, + 0X08, 0XC6, 0X08, 0XC6, 0X08, 0XE6, 0X08, 0XE6, 0X08, 0XE6, 0X08, 0XA5, + 0X08, 0XA4, 0X08, 0XA5, 0X08, 0XC5, 0X08, 0XC5, 0X08, 0XC5, 0X08, 0XE6, + 0X08, 0XE6, 0X08, 0XC6, 0X08, 0XC5, 0X08, 0XC6, 0X08, 0XC5, 0X08, 0XC5, + 0X08, 0XC5, 0X08, 0XA5, 0X08, 0XA4, 0X08, 0XC4, 0X10, 0XE6, 0X10, 0XE6, + 0X10, 0XE6, 0X11, 0X07, 0X19, 0X47, 0X19, 0X67, 0X21, 0XC9, 0X29, 0XC9, + 0X21, 0X87, 0X29, 0XA7, 0X29, 0XC7, 0X21, 0XA7, 0X31, 0XA6, 0X29, 0XA6, + 0X19, 0X86, 0X21, 0XC7, 0X29, 0XA6, 0X29, 0XA5, 0X29, 0XA6, 0X29, 0XE8, + 0X32, 0X29, 0X32, 0X08, 0X42, 0XA9, 0X4A, 0XC9, 0X21, 0X43, 0X31, 0XE5, + 0X42, 0X88, 0X29, 0XA5, 0X29, 0X84, 0X3A, 0X06, 0X3A, 0X26, 0X3A, 0X05, + 0X2A, 0X04, 0X29, 0XC4, 0X29, 0X44, 0X3A, 0X26, 0X3A, 0X06, 0X3A, 0X06, + 0X3A, 0X05, 0X53, 0X2A, 0X64, 0X0D, 0X53, 0X6B, 0X4A, 0XA8, 0X42, 0XE9, + 0X2A, 0X46, 0X21, 0X63, 0X42, 0XA8, 0X63, 0XAD, 0X4B, 0X09, 0X3A, 0X65, + 0X3A, 0X85, 0X53, 0X26, 0X63, 0X88, 0X5B, 0X88, 0X4A, 0XE8, 0X4B, 0X08, + 0X4B, 0X08, 0X52, 0X88, 0X5B, 0X08, 0X5B, 0X47, 0X42, 0X86, 0X53, 0X06, + 0X5B, 0X47, 0X5B, 0X47, 0X63, 0X67, 0X4B, 0X08, 0X42, 0XC7, 0X5B, 0X66, + 0X53, 0X27, 0X52, 0XC9, 0X6B, 0XCC, 0X6B, 0XEC, 0X6C, 0X0D, 0X74, 0X0D, + 0X6B, 0XEC, 0X74, 0X0D, 0X53, 0X4A, 0X4B, 0X2B, 0X63, 0XAB, 0X6B, 0XAC, + 0X5A, 0XEA, 0X6B, 0X6A, 0X6B, 0X8A, 0X6B, 0X8A, 0X6B, 0X69, 0X52, 0X87, + 0X53, 0X4C, 0X5B, 0X8D, 0X4B, 0X0A, 0X52, 0XC8, 0X52, 0XC8, 0X5B, 0X2A, + 0X59, 0XEB, 0X49, 0XAF, 0X51, 0XED, 0X52, 0X0F, 0X52, 0X0F, 0X62, 0X2C, + 0X72, 0XAB, 0X72, 0XC9, 0X5A, 0X0B, 0X51, 0XEA, 0X51, 0XEF, 0X59, 0XED, + 0X59, 0XEE, 0X52, 0X0E, 0X5A, 0X0B, 0X5A, 0X0B, 0X62, 0X2C, 0X5A, 0X0D, + 0X5A, 0X0D, 0X5A, 0X4D, 0X5A, 0XCB, 0X5A, 0XEA, 0X5B, 0X0C, 0X63, 0X4D, + 0X6B, 0X8C, 0X63, 0X6D, 0X63, 0X8D, 0X73, 0X2C, 0X6B, 0X8D, 0X63, 0XCE, + 0X4A, 0XAA, 0X73, 0XB2, 0X63, 0X50, 0X52, 0X8B, 0X52, 0X8A, 0X4A, 0X48, + 0X5A, 0XEA, 0X5A, 0XAC, 0X5A, 0XCD, 0X6B, 0X2B, 0X6B, 0X0C, 0X7B, 0XD4, + 0X73, 0X92, 0X5A, 0XEB, 0X63, 0X91, 0X63, 0X0F, 0X73, 0X92, 0X83, 0X51, + 0X82, 0XF1, 0X7B, 0X10, 0X72, 0XAE, 0X6A, 0X8E, 0X62, 0XCD, 0X83, 0X0F, + 0X8B, 0X0F, 0X8B, 0X0D, 0X8A, 0XCE, 0X82, 0XCE, 0X82, 0XCE, 0X8B, 0X71, + 0X83, 0X4F, 0X7B, 0X0F, 0X82, 0XCF, 0X72, 0XB2, 0X6A, 0XD0, 0X62, 0X74, + 0X6A, 0X94, 0X51, 0XEA, 0X41, 0X68, 0X6A, 0X6D, 0X73, 0X0C, 0X5A, 0X4C, + 0X31, 0X27, 0X41, 0X88, 0X39, 0X88, 0X41, 0X89, 0X41, 0XAB, 0X49, 0XAB, + 0X6A, 0X2B, 0X6A, 0X2B, 0X72, 0X2A, 0X39, 0X47, 0X31, 0X48, 0X41, 0XAA, + 0X39, 0X89, 0X41, 0X68, 0X41, 0X68, 0X41, 0X66, 0X39, 0X66, 0X41, 0XC8, + 0X41, 0XE9, 0X4A, 0X0B, 0X5A, 0X6D, 0X4A, 0XCF, 0X4A, 0X8E, 0X41, 0XC9, + 0X49, 0XE9, 0X51, 0XEA, 0X59, 0XCA, 0X8A, 0XCE, 0X82, 0XCE, 0X49, 0X88, + 0X41, 0X46, 0X72, 0X4C, 0X5A, 0X0C, 0X31, 0X05, 0X39, 0X47, 0X41, 0XCA, + 0X41, 0XC9, 0X39, 0X67, 0X39, 0X68, 0X41, 0X87, 0X41, 0X66, 0X51, 0XE7, + 0X62, 0X2C, 0X41, 0X6C, 0X39, 0X4A, 0X28, 0XE4, 0X4A, 0X07, 0X6B, 0X0B, + 0X6A, 0XA7, 0X72, 0XA7, 0X6A, 0XCC, 0X6A, 0XCB, 0X6A, 0XAB, 0X7B, 0X4E, + 0X5B, 0X0D, 0X5B, 0X0B, 0X6B, 0X8B, 0X7B, 0XED, 0X84, 0X2D, 0X63, 0X2E, + 0X5A, 0XCE, 0X63, 0X0D, 0X73, 0X0B, 0X6B, 0X2F, 0X63, 0X90, 0X73, 0X2C, + 0X8B, 0X6D, 0X73, 0X4C, 0X7B, 0X0B, 0X7B, 0X0D, 0X73, 0X2E, 0X72, 0X92, + 0X49, 0X8C, 0X62, 0X4C, 0X5A, 0X34, 0X42, 0X2D, 0X62, 0XEA, 0X5A, 0XB2, + 0X4A, 0XAF, 0X6A, 0XCC, 0X6B, 0X0C, 0X52, 0XAB, 0X42, 0X8A, 0X42, 0XAB, + 0X63, 0X2B, 0X52, 0XEA, 0X4B, 0X09, 0X53, 0X4A, 0X43, 0X2A, 0X53, 0X2B, + 0X53, 0X0A, 0X53, 0X2A, 0X53, 0X4A, 0X5B, 0X6B, 0X42, 0X68, 0X00, 0X20, + 0X4A, 0X06, 0X5A, 0X68, 0X52, 0X48, 0X52, 0XA9, 0X52, 0XAA, 0X5A, 0XA9, + 0X6A, 0XAA, 0X6A, 0XA9, 0X62, 0XA8, 0X5A, 0X89, 0X52, 0X69, 0X5A, 0X89, + 0X6A, 0XC9, 0X62, 0X89, 0X72, 0XEB, 0X7B, 0X0C, 0X6A, 0XCB, 0X5A, 0X8A, + 0X62, 0XAA, 0X5A, 0X69, 0X52, 0X07, 0X41, 0XC6, 0X39, 0X65, 0X49, 0XE7, + 0X62, 0X8A, 0X72, 0XCB, 0X7A, 0XCB, 0X8A, 0XEC, 0X83, 0X0C, 0X8B, 0X0D, + 0X52, 0X09, 0X51, 0XE8, 0X52, 0X08, 0X49, 0XE7, 0X41, 0XE7, 0X5A, 0X29, + 0X62, 0X4A, 0X62, 0X6B, 0X41, 0XC7, 0X52, 0X08, 0X6A, 0X8A, 0X62, 0X69, + 0X49, 0XC7, 0X5A, 0X29, 0X62, 0X69, 0X6A, 0X8A, 0X62, 0X29, 0X6A, 0X69, + 0X72, 0X6B, 0X72, 0X29, 0X6A, 0X6A, 0X6A, 0X6B, 0X83, 0X0B, 0X72, 0XAA, + 0X5A, 0X2A, 0X62, 0X2A, 0X49, 0XE8, 0X39, 0XA7, 0X39, 0XC8, 0X5A, 0XAA, + 0X62, 0XCA, 0X5A, 0X48, 0X41, 0XC7, 0X49, 0XE7, 0X49, 0XE7, 0X41, 0X87, + 0X41, 0XA7, 0X49, 0XE8, 0X5A, 0X6A, 0X49, 0XE8, 0X41, 0XA6, 0X4A, 0X09, + 0X5A, 0X6B, 0X5A, 0X48, 0X5A, 0X28, 0X52, 0X49, 0X52, 0X28, 0X51, 0XE7, + 0X4A, 0X09, 0X49, 0XE9, 0X52, 0X08, 0X52, 0X08, 0X52, 0X08, 0X4A, 0X08, + 0X52, 0X49, 0X4A, 0X08, 0X49, 0XE8, 0X49, 0XE9, 0X49, 0XE8, 0X52, 0X09, + 0X52, 0X0A, 0X52, 0X4A, 0X49, 0XE8, 0X49, 0XE9, 0X52, 0X09, 0X52, 0X09, + 0X52, 0X08, 0X6A, 0XAA, 0X5A, 0X69, 0X5A, 0X48, 0X5A, 0X69, 0X62, 0X69, + 0X62, 0X69, 0X5A, 0X49, 0X5A, 0X68, 0X52, 0X07, 0X5A, 0X28, 0X5A, 0X28, + 0X52, 0X28, 0X5A, 0X48, 0X62, 0X89, 0X4A, 0X08, 0X42, 0X08, 0X52, 0X28, + 0X62, 0X87, 0X62, 0X67, 0X62, 0X67, 0X7A, 0XA9, 0X5A, 0X48, 0X42, 0X08, + 0X4A, 0X07, 0X6A, 0X68, 0X62, 0X48, 0X5A, 0X28, 0X5A, 0X6A, 0X6A, 0X89, + 0X62, 0X69, 0X62, 0X69, 0X5A, 0X28, 0X52, 0X08, 0X52, 0X08, 0X41, 0XE7, + 0X41, 0XC8, 0X52, 0X29, 0X5A, 0X69, 0X5A, 0X6A, 0X52, 0X28, 0X52, 0X48, + 0X63, 0X0B, 0X5A, 0X69, 0X49, 0XC8, 0X18, 0X83, 0X21, 0X04, 0X62, 0XCB, + 0X49, 0XE7, 0X4A, 0X07, 0X63, 0X8E, 0X74, 0X51, 0X7C, 0X92, 0X84, 0XD3, + 0X7C, 0X30, 0X8C, 0XB2, 0X8C, 0XD2, 0X85, 0X17, 0X7C, 0XB5, 0X7C, 0X30, + 0X85, 0X18, 0X84, 0X53, 0X84, 0XB4, 0X5B, 0X4D, 0X5A, 0X69, 0X52, 0X48, + 0X6B, 0X4D, 0X7C, 0X52, 0X73, 0XD0, 0X5A, 0X68, 0X6C, 0X30, 0X6C, 0XB2, + 0X6B, 0XAE, 0X62, 0X8B, 0X6A, 0XAB, 0X74, 0X52, 0X6C, 0X32, 0X74, 0X11, + 0X7C, 0X70, 0X7C, 0X91, 0X73, 0XEF, 0X62, 0XEA, 0X52, 0X88, 0X52, 0X88, + 0X4A, 0X88, 0X4A, 0X67, 0X5A, 0XE9, 0X5B, 0X2A, 0X5B, 0X09, 0X5A, 0XC9, + 0X31, 0XC6, 0X5B, 0X07, 0X5A, 0XC7, 0X5A, 0XE9, 0X5B, 0X2C, 0X4B, 0XF5, + 0X4A, 0XC8, 0X52, 0XEA, 0X53, 0X09, 0X52, 0XE8, 0X52, 0XA8, 0X5A, 0XC8, + 0X6B, 0X29, 0X5A, 0XA9, 0X52, 0X48, 0X5A, 0XCB, 0X7B, 0XF3, 0X73, 0XD3, + 0X73, 0XF3, 0X73, 0XD3, 0X73, 0XD4, 0X5A, 0X8A, 0X62, 0XCB, 0X84, 0X12, + 0X6B, 0X09, 0X4A, 0X48, 0X73, 0X71, 0X83, 0XF3, 0X7C, 0X14, 0X63, 0X4E, + 0X39, 0XE5, 0X5A, 0XAA, 0X7B, 0X6F, 0X5A, 0X6A, 0X5A, 0X8B, 0X5A, 0X69, + 0X5A, 0X68, 0X62, 0X89, 0X6A, 0XCB, 0X5A, 0XAB, 0X3A, 0X47, 0X39, 0XC6, + 0X39, 0XA5, 0X5A, 0X48, 0X62, 0X89, 0X6B, 0X8F, 0X73, 0XB0, 0X52, 0XEB, + 0X42, 0X67, 0X5B, 0X09, 0X4A, 0XA7, 0X63, 0X0A, 0X83, 0XAF, 0X73, 0XB0, + 0X84, 0X75, 0X5B, 0X2C, 0X4A, 0X87, 0X52, 0X89, 0X52, 0XCA, 0X64, 0X54, + 0X64, 0X96, 0X5B, 0X2C, 0X52, 0X87, 0X6B, 0X4F, 0X5B, 0X0D, 0X4A, 0XEB, + 0X53, 0X0C, 0X53, 0X0B, 0X52, 0XA9, 0X52, 0X87, 0X52, 0XC8, 0X63, 0X2A, + 0X63, 0X09, 0X63, 0X29, 0X63, 0X2B, 0X63, 0X0A, 0X63, 0X4D, 0X62, 0XC9, + 0X5A, 0X87, 0X5A, 0XE8, 0X73, 0XF0, 0X7C, 0X10, 0X7B, 0XCB, 0X6B, 0XAB, + 0X6B, 0XCD, 0X6B, 0XAD, 0X73, 0X8C, 0X73, 0XAB, 0X6B, 0X8A, 0X73, 0XAA, + 0X5A, 0XE9, 0X42, 0X28, 0X42, 0X27, 0X42, 0X07, 0X52, 0X68, 0X52, 0X08, + 0X52, 0X48, 0X52, 0X68, 0X52, 0X49, 0X52, 0X69, 0X41, 0XE6, 0X41, 0XE6, + 0X41, 0XE6, 0X39, 0XE5, 0X31, 0X85, 0X08, 0X20, 0X00, 0X00, 0X08, 0X42, + 0X10, 0X83, 0X18, 0X83, 0X39, 0X66, 0X41, 0XC8, 0X41, 0XA8, 0X39, 0X87, + 0X39, 0X46, 0X31, 0X46, 0X49, 0XC9, 0X51, 0XA7, 0X51, 0XEA, 0X52, 0X2C, + 0X5A, 0X0A, 0X52, 0X0B, 0X5A, 0X08, 0X62, 0X09, 0X62, 0X09, 0X5A, 0X0A, + 0X52, 0X0B, 0X52, 0X0B, 0X51, 0XC9, 0X59, 0XEB, 0X5A, 0X4A, 0X52, 0X28, + 0X52, 0X29, 0X5A, 0X88, 0X5A, 0XA9, 0X4A, 0X89, 0X4A, 0X89, 0X4A, 0X69, + 0X52, 0XA9, 0X5B, 0X0A, 0X5A, 0XEA, 0X6A, 0XEA, 0X73, 0X2A, 0X7B, 0XAC, + 0X62, 0XEC, 0X52, 0XAC, 0X4A, 0XCB, 0X4B, 0X0C, 0X4A, 0XED, 0X5B, 0X0C, + 0X5B, 0X0C, 0X5B, 0X2D, 0X5B, 0X6D, 0X63, 0X6D, 0X5B, 0X8D, 0X5B, 0X0C, + 0X5A, 0XEC, 0X63, 0X6C, 0X5B, 0X4B, 0X52, 0XEA, 0X53, 0X0A, 0X53, 0X0B, + 0X5B, 0X0C, 0X5B, 0X0C, 0X5A, 0XEB, 0X4A, 0XC9, 0X42, 0XC9, 0X42, 0XC9, + 0X4A, 0XEA, 0X6B, 0X4E, 0X5A, 0XEB, 0X5A, 0XEC, 0X5A, 0XAA, 0X6A, 0XCA, + 0X73, 0X0B, 0X6A, 0XEB, 0X6A, 0XEB, 0X73, 0X2B, 0X7B, 0X2B, 0X5A, 0XCA, + 0X52, 0XC9, 0X5A, 0XEB, 0X62, 0XEC, 0X5A, 0X8A, 0X5A, 0X68, 0X5A, 0X68, + 0X5A, 0X68, 0X5A, 0X68, 0X5A, 0X68, 0X52, 0X8A, 0X42, 0X6A, 0X5A, 0XCA, + 0X73, 0X4C, 0X62, 0XCA, 0X5A, 0X69, 0X5A, 0X69, 0X42, 0X6A, 0X42, 0X8A, + 0X52, 0X69, 0X52, 0X88, 0X52, 0X89, 0X5A, 0X69, 0X52, 0XC8, 0X62, 0XEB, + 0X52, 0XAB, 0X4A, 0X8A, 0X52, 0XEC, 0X53, 0X90, 0X5B, 0X91, 0X5B, 0X91, + 0X53, 0X91, 0X6C, 0X55, 0X64, 0X35, 0X5C, 0X17, 0X5C, 0X18, 0X53, 0X73, + 0X5A, 0XEE, 0X73, 0XB3, 0X7B, 0XB3, 0X6B, 0X50, 0X7B, 0XB1, 0X7B, 0XF1, + 0X7B, 0X6F, 0X7C, 0X34, 0X74, 0XB6, 0X73, 0X6F, 0X62, 0XEF, 0X62, 0XAE, + 0X52, 0X90, 0X42, 0X92, 0X52, 0X90, 0X5A, 0X8F, 0X62, 0XCF, 0X52, 0X70, + 0X52, 0X71, 0X6A, 0XCD, 0X6A, 0X8D, 0X6A, 0X8C, 0X5A, 0X6F, 0X3A, 0X53, + 0X42, 0X71, 0X62, 0XAE, 0X62, 0X6D, 0X72, 0XAC, 0X6A, 0XCD, 0X42, 0X91, + 0X52, 0X8F, 0X62, 0X6D, 0X62, 0X8E, 0X52, 0X6F, 0X3A, 0X30, 0X4A, 0X0D, + 0X32, 0X51, 0X4A, 0XB1, 0X62, 0X8E, 0X4A, 0XAF, 0X32, 0X70, 0X6A, 0X2B, + 0X51, 0XEA, 0X2A, 0X0F, 0X3A, 0X4E, 0X5B, 0X2F, 0X62, 0XEE, 0X5A, 0XCD, + 0X5B, 0X0E, 0X4A, 0XCA, 0X3A, 0X27, 0X3A, 0X27, 0X4A, 0X48, 0X4A, 0X69, + 0X42, 0X89, 0X4A, 0X08, 0X52, 0X49, 0X62, 0XCC, 0X4A, 0X08, 0X73, 0X0D, + 0X83, 0X6F, 0X83, 0X4F, 0X7B, 0X2E, 0X83, 0X2E, 0X6A, 0XAB, 0X39, 0XE8, + 0X41, 0XC8, 0X5A, 0XAB, 0X73, 0X90, 0X73, 0X70, 0X73, 0X0F, 0X6B, 0X30, + 0X6B, 0X51, 0X52, 0X4E, 0X5A, 0X8E, 0X3A, 0X71, 0X32, 0X31, 0X63, 0XB5, + 0X6B, 0X94, 0X52, 0X0C, 0X52, 0X4C, 0X3A, 0X32, 0X42, 0X2F, 0X73, 0X73, + 0X52, 0XD3, 0X4A, 0X52, 0X73, 0X74, 0X6B, 0X55, 0X62, 0XF0, 0X73, 0X52, + 0X73, 0XD5, 0X52, 0X2C, 0X52, 0X2D, 0X5A, 0X2D, 0X62, 0X2E, 0X59, 0XED, + 0X5A, 0X2D, 0X4A, 0X50, 0X3A, 0XB5, 0X4A, 0XB2, 0X5A, 0XB1, 0X62, 0XB0, + 0X3A, 0X96, 0X4A, 0X92, 0X5A, 0X6D, 0X5A, 0X4D, 0X4A, 0X93, 0X32, 0XB7, + 0X4A, 0X72, 0X52, 0X0D, 0X39, 0XCB, 0X42, 0X4B, 0X4A, 0XCA, 0X52, 0XE9, + 0X63, 0X0C, 0X52, 0XAE, 0X5B, 0X32, 0X53, 0XB6, 0X6B, 0XB2, 0X73, 0XB0, + 0X73, 0XB0, 0X73, 0X8F, 0X6B, 0X4E, 0X63, 0X0D, 0X6B, 0X2C, 0X74, 0X32, + 0X74, 0X97, 0X6C, 0X78, 0X75, 0X1A, 0X7D, 0X7B, 0X7D, 0X1A, 0X6C, 0X35, + 0X63, 0X30, 0X7B, 0X0E, 0X7C, 0X13, 0X74, 0X15, 0X6B, 0X72, 0X73, 0X92, + 0X73, 0X92, 0X7B, 0XB0, 0X6B, 0X0F, 0X6A, 0X8C, 0X6A, 0X8F, 0X62, 0XB0, + 0X62, 0X6C, 0X8A, 0XAD, 0X72, 0X08, 0X6A, 0X90, 0X6A, 0X8E, 0X6A, 0X2A, + 0X7B, 0X0F, 0X7B, 0XB4, 0X73, 0X2F, 0X83, 0X6F, 0X7B, 0X0D, 0X6A, 0XEF, + 0X6B, 0X94, 0X84, 0X55, 0X73, 0XF5, 0X74, 0X39, 0X85, 0X1A, 0X7C, 0X53, + 0X73, 0XD2, 0X73, 0X90, 0X7B, 0X8F, 0X74, 0X13, 0X74, 0X37, 0X74, 0X79, + 0X74, 0X97, 0X7C, 0X76, 0X7C, 0X75, 0X7B, 0XF1, 0X63, 0X50, 0X6B, 0XF3, + 0X74, 0X96, 0X73, 0X30, 0X63, 0X12, 0X63, 0X31, 0X6A, 0XF0, 0X72, 0X8F, + 0X83, 0XB0, 0X8C, 0X30, 0X73, 0XF4, 0X7C, 0X37, 0X8C, 0X76, 0X84, 0XB9, + 0X7C, 0X78, 0X7C, 0X57, 0X6B, 0XD4, 0X53, 0X30, 0X63, 0X73, 0X5A, 0X72, + 0X5A, 0XB0, 0X5A, 0XB1, 0X5A, 0X70, 0X63, 0X10, 0X8C, 0XF6, 0X72, 0XEC, + 0X7B, 0X2E, 0X9C, 0X97, 0X84, 0X12, 0X84, 0X30, 0X7C, 0X11, 0X7C, 0X33, + 0X85, 0X19, 0X85, 0X3A, 0X6B, 0X6E, 0X7C, 0XFB, 0X7C, 0X54, 0X73, 0X4C, + 0X6A, 0XE9, 0X5A, 0XA8, 0X6B, 0X4D, 0X84, 0X12, 0X84, 0X31, 0X83, 0XF0, + 0X8B, 0XEF, 0X8B, 0XED, 0X7C, 0X52, 0X74, 0X32, 0X74, 0X31, 0X6A, 0XF0, + 0X5A, 0X0B, 0X62, 0X6D, 0X62, 0XD2, 0X5A, 0X91, 0X62, 0XB1, 0X6A, 0XEF, + 0X72, 0XEC, 0X7B, 0XB1, 0X83, 0XF4, 0X8B, 0X73, 0X7B, 0XD1, 0X7B, 0XB0, + 0X7B, 0XF4, 0X84, 0X55, 0X94, 0XD4, 0X94, 0X95, 0X7B, 0XB4, 0X83, 0XD5, + 0X94, 0X54, 0X8C, 0X33, 0X8C, 0X74, 0X7B, 0XB0, 0X6C, 0XD9, 0X8D, 0XDD, + 0X7C, 0X78, 0X6B, 0XD3, 0X7B, 0XF2, 0X6B, 0X52, 0X63, 0X11, 0X74, 0X54, + 0X63, 0XF5, 0X63, 0XD4, 0X7C, 0X54, 0X62, 0XF1, 0X7C, 0X12, 0X63, 0X32, + 0X4A, 0X8D, 0X52, 0X8D, 0X52, 0X0E, 0X62, 0XB1, 0X8A, 0XD0, 0X9B, 0X93, + 0X7B, 0XB4, 0X73, 0XD4, 0X7C, 0X56, 0X7B, 0XF3, 0X6B, 0X6F, 0X6B, 0X2F, + 0X72, 0XEC, 0X83, 0XCD, 0X73, 0X6C, 0X6B, 0X0D, 0X73, 0X32, 0X5A, 0X4F, + 0X63, 0X50, 0X73, 0XD2, 0X62, 0XAE, 0X6A, 0X6E, 0X72, 0X8D, 0X62, 0X73, + 0X62, 0XB3, 0X6A, 0XD3, 0X72, 0XD3, 0X6A, 0XD3, 0X62, 0XB3, 0X72, 0XD3, + 0X62, 0X93, 0X73, 0X50, 0X83, 0X52, 0X83, 0XD4, 0X8C, 0X11, 0X72, 0XD1, + 0X73, 0X15, 0X52, 0X72, 0X4A, 0X10, 0X5A, 0XF2, 0X7C, 0X55, 0X8C, 0X54, + 0X73, 0X10, 0X5A, 0X91, 0X5A, 0X72, 0X5A, 0X51, 0X7B, 0X12, 0X73, 0X73, + 0X53, 0X53, 0X7B, 0XF1, 0X5B, 0X91, 0X5B, 0X55, 0X6B, 0X57, 0X63, 0X56, + 0X52, 0X92, 0X62, 0X95, 0X5A, 0XB3, 0X5A, 0XB2, 0X52, 0X71, 0X63, 0X54, + 0X6B, 0XB4, 0X52, 0XF1, 0X52, 0X51, 0X4A, 0X71, 0X52, 0XD3, 0X5A, 0X92, + 0X62, 0XB1, 0X63, 0XB3, 0X74, 0X13, 0X83, 0X8E, 0X8C, 0X11, 0X73, 0X6D, + 0X73, 0X8D, 0X73, 0XF3, 0X63, 0X15, 0X62, 0XD3, 0X73, 0XB2, 0X5B, 0X13, + 0X6B, 0X91, 0X7B, 0XF1, 0X7B, 0X90, 0X6B, 0X2E, 0X73, 0X0E, 0X7B, 0X0D, + 0X73, 0X4F, 0X7C, 0X56, 0X73, 0XD4, 0X62, 0XCC, 0X73, 0X4C, 0X83, 0XAE, + 0X7B, 0XCE, 0X7B, 0XCF, 0X7B, 0X90, 0X7B, 0XB1, 0X7B, 0XF1, 0X8B, 0XCD, + 0X84, 0X76, 0X74, 0X7A, 0X7C, 0X59, 0X7C, 0X37, 0X53, 0X14, 0X52, 0X91, + 0X62, 0XD1, 0X8B, 0X4D, 0X73, 0X8F, 0X73, 0XB0, 0X93, 0XCE, 0X8B, 0XF0, + 0X8C, 0X0F, 0X93, 0X6A, 0X83, 0XAD, 0X94, 0X10, 0X8B, 0XD0, 0X73, 0X4E, + 0X73, 0X8E, 0X73, 0X6C, 0X6C, 0X30, 0X73, 0XAF, 0X7B, 0X8E, 0X73, 0XCF, + 0X73, 0X0B, 0X7B, 0XD0, 0X7C, 0X13, 0X7B, 0XF0, 0X84, 0X50, 0X7B, 0X6E, + 0X73, 0X4F, 0XA3, 0X6C, 0X8C, 0X11, 0X6B, 0X90, 0X64, 0X17, 0X6C, 0X59, + 0X5C, 0X17, 0X6B, 0X90, 0X5B, 0X94, 0X5C, 0X38, 0X64, 0X16, 0X5B, 0X70, + 0X52, 0XCB, 0X73, 0X8F, 0X63, 0X4D, 0X5B, 0X2F, 0X5B, 0X70, 0X5B, 0X8F, + 0X63, 0X2F, 0X63, 0XAE, 0X53, 0X0D, 0X6C, 0X14, 0X74, 0X97, 0X73, 0XF1, + 0X7C, 0X12, 0X7C, 0X34, 0X7C, 0X75, 0X7D, 0X3A, 0X74, 0X32, 0X52, 0XCB, + 0X29, 0XC6, 0X29, 0XE6, 0X3A, 0X48, 0X7B, 0XCE, 0X7B, 0XCF, 0X7B, 0X8E, + 0X7B, 0X8D, 0X6B, 0X6C, 0X6B, 0X6B, 0X7B, 0XF0, 0X84, 0X94, 0X7C, 0X32, + 0X7C, 0X53, 0X84, 0X94, 0X8D, 0X58, 0X95, 0X36, 0X9D, 0X74, 0X84, 0XD1, + 0X74, 0X4E, 0X74, 0X4E, 0X8C, 0XD1, 0X84, 0X90, 0X6C, 0X0E, 0X74, 0X91, + 0X7C, 0XF2, 0X63, 0XED, 0X5B, 0X2B, 0X74, 0X50, 0X7C, 0X70, 0X74, 0X4F, + 0X74, 0X4F, 0X74, 0X50, 0X7C, 0XB2, 0X74, 0X30, 0X6B, 0XCE, 0X74, 0X52, + 0X74, 0XB4, 0X74, 0XB4, 0X74, 0XB4, 0X7C, 0XB2, 0X7C, 0X92, 0X6B, 0X8D, + 0X7C, 0X31, 0X7C, 0X72, 0X74, 0X72, 0X6C, 0X72, 0X74, 0X30, 0X74, 0X0F, + 0X74, 0XB4, 0X73, 0XCE, 0X7C, 0X50, 0X84, 0X70, 0X7C, 0X71, 0X6C, 0X31, + 0X74, 0X31, 0X7C, 0X50, 0X7C, 0X10, 0X6B, 0XCE, 0X74, 0X0E, 0X74, 0X94, + 0X74, 0X31, 0X74, 0X10, 0X74, 0X30, 0X74, 0X30, 0X74, 0X32, 0X6C, 0X32, + 0X74, 0X72, 0X8C, 0XB1, 0X94, 0XB1, 0X8C, 0X92, 0X8C, 0X92, 0X94, 0XB1, + 0X94, 0X91, 0X95, 0X15, 0X7C, 0X71, 0X7C, 0X91, 0X94, 0XF3, 0X94, 0XF3, + 0X94, 0XF3, 0X9D, 0X14, 0X9D, 0X34, 0XA5, 0X55, 0XAD, 0X76, 0X9D, 0X35, + 0X94, 0XD3, 0X94, 0XF3, 0X94, 0XF4, 0X95, 0X14, 0X9D, 0X14, 0X94, 0XF3, + 0X7C, 0X92, 0X74, 0X2F, 0X74, 0X0F, 0X84, 0XF3, 0X8C, 0XD2, 0X8C, 0X6F, + 0X74, 0X50, 0X74, 0X50, 0X74, 0X0F, 0X7C, 0X51, 0X7C, 0X50, 0X8C, 0XD4, + 0X9D, 0X56, 0X84, 0XD4, 0X6C, 0X0F, 0X6C, 0X50, 0X74, 0X50, 0X74, 0X50, + 0X74, 0X2F, 0X6B, 0XEE, 0X74, 0X0E, 0X74, 0X2E, 0X7C, 0X92, 0X74, 0XB4, + 0X74, 0X72, 0X74, 0X71, 0X7C, 0X71, 0X84, 0XB2, 0X84, 0XF3, 0X84, 0XF3, + 0X84, 0XF4, 0X84, 0XB2, 0X7C, 0X6F, 0X7C, 0XD3, 0X7C, 0X92, 0X5A, 0X26, + 0X6B, 0X29, 0X85, 0X13, 0X84, 0XF2, 0X84, 0XF3, 0X8D, 0X13, 0X8D, 0X11, + 0X9D, 0X95, 0X9D, 0XB5, 0X9D, 0XB6, 0X9D, 0XB6, 0X9D, 0XB6, 0X9D, 0XB6, + 0X9D, 0XD6, 0X9D, 0XD6, 0X95, 0X95, 0XA6, 0X99, 0X85, 0X54, 0X3A, 0X06, + 0X63, 0XCE, 0X7C, 0XD1, 0X7C, 0XD1, 0X7C, 0XF2, 0X74, 0X90, 0X74, 0XB1, + 0X7C, 0X90, 0X7C, 0X70, 0X53, 0X0A, 0X42, 0X27, 0X74, 0XB2, 0X7C, 0XD1, + 0X74, 0X90, 0X74, 0X91, 0X74, 0XB2, 0X6C, 0XD3, 0X6C, 0XB2, 0X74, 0XF4, + 0X7D, 0XB8, 0X85, 0X95, 0X75, 0X13, 0X75, 0XD7, 0X64, 0XD2, 0X7D, 0X74, + 0X85, 0X95, 0X7D, 0X75, 0X6C, 0XB2, 0X64, 0X91, 0X64, 0X50, 0X5C, 0XF7, + 0X6D, 0X58, 0X7D, 0X36, 0X7D, 0X35, 0X65, 0X37, 0X64, 0XD2, 0X64, 0X92, + 0X64, 0X71, 0X5B, 0XAD, 0X5B, 0XAD, 0X6B, 0XEE, 0X6C, 0X2F, 0X64, 0X2F, + 0X5B, 0XEE, 0X42, 0XE9, 0X3A, 0X68, 0X3A, 0X68, 0X32, 0X68, 0X7C, 0X50, + 0X95, 0X34, 0X95, 0X34, 0X95, 0X14, 0X95, 0X14, 0X95, 0X14, 0X95, 0X34, + 0X8D, 0X13, 0X95, 0X13, 0X74, 0X2F, 0X3A, 0X06, 0X42, 0X27, 0X3A, 0X06, + 0X4A, 0XA9, 0X63, 0XAD, 0X63, 0XAC, 0X63, 0X8C, 0X63, 0XAC, 0X5B, 0X6B, + 0X31, 0XC6, 0X39, 0XE6, 0X5B, 0X2A, 0X5B, 0X4A, 0X4A, 0X68, 0X42, 0X27, + 0X42, 0X07, 0X42, 0X06, 0X3A, 0X06, 0X42, 0X06, 0X39, 0XE6, 0X31, 0XE6, + 0X3A, 0X06, 0X3A, 0X06, 0X3A, 0X26, 0X31, 0XE6, 0X31, 0XC5, 0X39, 0XE5, + 0X42, 0X06, 0X42, 0X06, 0X4A, 0X26, 0X4A, 0X25, 0X4A, 0X26, 0X52, 0X46, + 0X52, 0X66, 0X42, 0X47, 0X42, 0X06, 0X41, 0XC5, 0X4A, 0X46, 0X4A, 0X26, + 0X49, 0XE6, 0X7C, 0X10, 0X9D, 0X34, 0X9D, 0X34, 0X9D, 0X14, 0X8C, 0X71, + 0X7B, 0XEF, 0X7B, 0XEF, 0X6B, 0X4C, 0X5A, 0XA9, 0X42, 0X48, 0X42, 0X47, + 0X3A, 0X06, 0X3A, 0X06, 0X42, 0X47, 0X42, 0X27, 0X5B, 0X0A, 0X73, 0XCC, + 0X6B, 0X6B, 0X42, 0X06, 0X39, 0XE6, 0X4A, 0X67, 0X73, 0X8B, 0X73, 0X6B, + 0X52, 0XA8, 0X42, 0X47, 0X42, 0X27, 0X42, 0X68, 0X5B, 0X2B, 0X5B, 0X8D, + 0X73, 0XAC, 0X83, 0XCA, 0X8D, 0X55, 0X85, 0X97, 0X75, 0X16, 0X7C, 0X2E, + 0X7B, 0XED, 0X7C, 0X0E, 0X7C, 0X0E, 0X7B, 0XEE, 0X7C, 0X0E, 0X7C, 0X0D, + 0X8C, 0X2C, 0X8C, 0X4C, 0X8C, 0X4C, 0X8C, 0XB2, 0X8C, 0XF4, 0X8C, 0XD2, + 0X8C, 0X4D, 0X8C, 0XD2, 0X7C, 0XD2, 0X74, 0X50, 0X7C, 0X4F, 0X7C, 0X4E, + 0X7C, 0X4F, 0X84, 0X4F, 0X7C, 0X71, 0X74, 0X51, 0X74, 0X30, 0X74, 0X52, + 0X74, 0X0F, 0X6B, 0XED, 0X6C, 0X0F, 0X6C, 0X0F, 0X73, 0XCC, 0X7B, 0XAA, + 0X7B, 0XAB, 0X7B, 0XAA, 0X84, 0X70, 0X7C, 0X70, 0X73, 0X8B, 0X73, 0XAC, + 0X7B, 0XEE, 0X7C, 0X0E, 0X7C, 0X0E, 0X84, 0X0E, 0X83, 0XED, 0X84, 0X0D, + 0X84, 0XB2, 0X7C, 0XB2, 0X7C, 0X90, 0X84, 0XB1, 0X7C, 0X91, 0X6C, 0X51, + 0X6C, 0X30, 0X6C, 0X30, 0X73, 0XEF, 0X6B, 0XCF, 0X63, 0X8E, 0X74, 0X30, + 0X74, 0X51, 0X74, 0X4F, 0X7C, 0X91, 0X74, 0X2F, 0X74, 0X2E, 0X7C, 0X4F, + 0X7C, 0X4F, 0X7C, 0X70, 0X7C, 0X4E, 0X73, 0X89, 0X7C, 0X4E, 0X74, 0X2E, + 0X5B, 0X6B, 0X5B, 0X8C, 0X53, 0X4A, 0X63, 0X69, 0X6B, 0XCB, 0X73, 0XEC, + 0X83, 0XCB, 0X83, 0XEB, 0X7B, 0XEB, 0X74, 0X0C, 0X6B, 0X8B, 0X63, 0X4A, + 0X52, 0XEA, 0X42, 0X06, 0X4A, 0X47, 0X6B, 0X4A, 0X7B, 0XEC, 0X7B, 0XED, + 0X7B, 0XAB, 0X6B, 0X8D, 0X63, 0X8E, 0X4A, 0X88, 0X42, 0X47, 0X4A, 0X67, + 0X4A, 0X67, 0X4A, 0X67, 0X4A, 0X67, 0X42, 0XC9, 0X3A, 0X47, 0X3A, 0X27, + 0X42, 0X88, 0X4A, 0X87, 0X52, 0XE9, 0X5B, 0X09, 0X5B, 0X09, 0X63, 0X4A, + 0X63, 0X09, 0X42, 0X47, 0X42, 0X68, 0X4A, 0X68, 0X73, 0XAA, 0X83, 0XEB, + 0X73, 0X8A, 0X4A, 0X46, 0X4A, 0X46, 0X42, 0X26, 0X73, 0X8A, 0X5A, 0XE8, + 0X52, 0X87, 0X5A, 0XC7, 0X7C, 0X0C, 0X73, 0XED, 0X6B, 0X8C, 0X73, 0X8B, + 0X73, 0XCD, 0X73, 0X6B, 0X7B, 0X69, 0X63, 0X09, 0X39, 0XE6, 0X52, 0XA8, + 0X62, 0XE9, 0X42, 0X27, 0X4A, 0X48, 0X4A, 0X47, 0X4A, 0X67, 0X4A, 0X46, + 0X63, 0X0A, 0X7B, 0XCE, 0X73, 0X8D, 0X84, 0X30, 0X84, 0X0F, 0X8C, 0X71, + 0X9C, 0XF3, 0X84, 0X51, 0X63, 0X6E, 0X53, 0X2E, 0X2A, 0X2A, 0X21, 0XE9, + 0X22, 0X0A, 0X21, 0XC8, 0X31, 0X84, 0X21, 0X86, 0X09, 0X68, 0X09, 0X47, + 0X09, 0X27, 0X11, 0XA8, 0X22, 0X09, 0X22, 0X09, 0X22, 0X09, 0X22, 0X09, + 0X22, 0X0A, 0X2A, 0X0B, 0X21, 0XEA, 0X19, 0XA9, 0X19, 0XA8, 0X19, 0XA8, + 0X19, 0XA9, 0X22, 0X0A, 0X31, 0XE8, 0X21, 0XA7, 0X21, 0XE8, 0X29, 0X85, + 0X29, 0XA6, 0X2A, 0X09, 0X21, 0XE9, 0X19, 0XC9, 0X19, 0XA9, 0X11, 0X88, + 0X19, 0XA8, 0X29, 0XE7, 0X29, 0XE7, 0X19, 0XA7, 0X29, 0XE8, 0X19, 0XE9, + 0X19, 0XE9, 0X19, 0XC9, 0X21, 0XA8, 0X21, 0XA8, 0X19, 0XA8, 0X09, 0X47, + 0X00, 0X61, 0X00, 0X20, 0X21, 0X45, 0X29, 0X85, 0X29, 0X85, 0X29, 0X85, + 0X29, 0X85, 0X29, 0XA6, 0X5B, 0X2A, 0X63, 0X8B, 0X73, 0XAB, 0X6B, 0X6B, + 0X74, 0X51, 0X6B, 0XF0, 0X63, 0X8D, 0X64, 0X30, 0X64, 0X10, 0X64, 0X10, + 0X64, 0X10, 0X5B, 0XF0, 0X6B, 0X8C, 0X6B, 0X8B, 0X6B, 0XAD, 0X6B, 0XCE, + 0X5B, 0X8D, 0X63, 0X8D, 0X63, 0X8C, 0X63, 0XAD, 0X63, 0XED, 0X5B, 0XAC, + 0X6C, 0X2E, 0X6C, 0X0E, 0X63, 0XCD, 0X5B, 0XCB, 0X52, 0XE9, 0X5B, 0X4A, + 0X63, 0X09, 0X42, 0X26, 0X3A, 0X06, 0X63, 0XAC, 0X6C, 0X50, 0X74, 0X0E, + 0X84, 0XD2, 0X63, 0X8D, 0X7C, 0X2F, 0X6C, 0X92, 0X64, 0X52, 0X64, 0X11, + 0X74, 0X94, 0X5B, 0X0A, 0X49, 0XA1, 0X51, 0XE3, 0X5A, 0XA7, 0X6B, 0X6A, + 0X6B, 0X4A, 0X63, 0X09, 0X7C, 0X0D, 0X9D, 0X53, 0X8C, 0XB0, 0X84, 0X0C, + 0X84, 0X4E, 0X9D, 0X12, 0X95, 0X12, 0X7C, 0X51, 0X6B, 0XCE, 0X6B, 0XCE, + 0X7C, 0X50, 0XB5, 0XD6, 0X9D, 0X34, 0X8C, 0XB2, 0X84, 0X70, 0X7C, 0X30, + 0X84, 0X50, 0X73, 0XEE, 0X73, 0XEF, 0X84, 0X51, 0X84, 0X51, 0X94, 0XF4, + 0XA5, 0XB7, 0X95, 0X34, 0X95, 0X34, 0X9D, 0X75, 0X9D, 0XD7, 0X9D, 0XD7, + 0X9D, 0XB7, 0X9D, 0XB6, 0XA5, 0XF7, 0X8C, 0XF3, 0X7C, 0X71, 0X7C, 0X6F, + 0X6B, 0XAA, 0X6B, 0XCB, 0X6B, 0XCB, 0X6B, 0XCB, 0X63, 0X6A, 0X4A, 0XA8, + 0X42, 0X67, 0X42, 0X47, 0X5A, 0XE7, 0X5A, 0XA7, 0X63, 0X2A, 0X74, 0X4E, + 0X63, 0XAC, 0X52, 0X46, 0X63, 0XCC, 0X62, 0XC7, 0X63, 0X08, 0X74, 0X0E, + 0X73, 0XCD, 0X6B, 0X8B, 0X6B, 0XAC, 0X6B, 0XAC, 0X6C, 0X30, 0X74, 0X72, + 0X84, 0X50, 0X94, 0XB2, 0X94, 0XD2, 0X6B, 0XAC, 0X63, 0X4B, 0X63, 0X6B, + 0X5A, 0X87, 0X52, 0X66, 0X5A, 0X86, 0X62, 0XE8, 0X62, 0XE8, 0X62, 0XE8, + 0X63, 0X2A, 0X6C, 0X73, 0X63, 0XCF, 0X52, 0X88, 0X52, 0XC9, 0X52, 0XC8, + 0X52, 0XA7, 0X52, 0XA7, 0X42, 0X46, 0X52, 0XC8, 0X7C, 0X2F, 0X7C, 0X30, + 0X74, 0X0F, 0X74, 0X50, 0X74, 0X30, 0X84, 0X2E, 0X7C, 0X2E, 0X74, 0X2E, + 0X7C, 0X4F, 0X7C, 0X90, 0X7C, 0X90, 0X95, 0X33, 0X95, 0X34, 0X85, 0X56, + 0X8D, 0X55, 0X8D, 0X77, 0X9D, 0XF8, 0X84, 0X90, 0X73, 0X4B, 0X85, 0X34, + 0X7C, 0X4F, 0X7B, 0XCD, 0X7C, 0X92, 0X8D, 0XB8, 0X84, 0X90, 0X74, 0X0D, + 0X6B, 0X49, 0X84, 0X50, 0X85, 0X36, 0X6B, 0XAD, 0X74, 0XB2, 0X8E, 0X19, + 0X75, 0X14, 0X64, 0X51, 0X6C, 0X71, 0X74, 0X92, 0X73, 0XEE, 0X5A, 0XC7, + 0X6B, 0XAC, 0X84, 0XB1, 0X74, 0X0F, 0X6C, 0X2F, 0X74, 0X4F, 0X84, 0XF2, + 0X6C, 0XB4, 0X7D, 0X16, 0X8D, 0X34, 0X6C, 0X0F, 0X4A, 0XCA, 0X4A, 0X69, + 0X4A, 0X68, 0X5A, 0XC9, 0X5B, 0X0B, 0X5B, 0X0B, 0X63, 0X0A, 0X63, 0X4C, + 0X6B, 0X8D, 0X63, 0X0A, 0X62, 0XC9, 0X4A, 0X68, 0X4A, 0X68, 0X4A, 0XA9, + 0X4A, 0XA9, 0X4A, 0XA9, 0X4A, 0XCA, 0X4A, 0XA9, 0X4A, 0X89, 0X4A, 0XA9, + 0X52, 0XCA, 0X52, 0XEA, 0X4A, 0X89, 0X4A, 0XCA, 0X42, 0XA9, 0X52, 0X88, + 0X4A, 0X89, 0X4A, 0X68, 0X4A, 0X89, 0X4A, 0XAA, 0X4A, 0XA9, 0X4A, 0X89, + 0X3A, 0X29, 0X42, 0X8B, 0X3A, 0X49, 0X3A, 0X29, 0X32, 0X29, 0X3A, 0X8B, + 0X74, 0X2F, 0X64, 0X11, 0X4A, 0X8A, 0X3A, 0X28, 0X4A, 0X69, 0X4A, 0X89, + 0X3A, 0X49, 0X3A, 0X49, 0X42, 0X6A, 0X52, 0XEC, 0X5B, 0X8F, 0X6C, 0X75, + 0X5B, 0X6D, 0X52, 0XCA, 0X52, 0XC9, 0X4A, 0X27, 0X4A, 0X47, 0X52, 0X67, + 0X52, 0X47, 0X52, 0X67, 0X52, 0X06, 0X5A, 0XA9, 0X63, 0XCE, 0X63, 0X8D, + 0X5A, 0XEA, 0X52, 0XA8, 0X52, 0X67, 0X4A, 0X47, 0X52, 0XA8, 0X52, 0XA8, + 0X4A, 0X67, 0X4A, 0X68, 0X4A, 0X88, 0X4A, 0X47, 0X42, 0X27, 0X84, 0XB2, + 0X9D, 0X54, 0X9D, 0X55, 0XA5, 0X95, 0XA5, 0X75, 0X94, 0XF3, 0X94, 0XD2, + 0X94, 0XD2, 0X94, 0XD2, 0X94, 0XB2, 0X63, 0XAF, 0X32, 0X6A, 0X42, 0X48, + 0X52, 0XEA, 0X63, 0X4C, 0X6B, 0X6D, 0X6B, 0X4C, 0X5A, 0XEA, 0X63, 0X0A, + 0X4A, 0XAB, 0X42, 0X49, 0X42, 0X48, 0X42, 0X28, 0X42, 0X48, 0X42, 0X48, + 0X3A, 0X07, 0X3A, 0X08, 0X42, 0X29, 0X42, 0X28, 0X39, 0XE8, 0X39, 0XE7, + 0X39, 0XE7, 0X39, 0XC7, 0X39, 0XC7, 0X39, 0XC7, 0X39, 0XE8, 0X41, 0XE8, + 0X52, 0X6A, 0X4A, 0X48, 0X41, 0XE7, 0X42, 0X07, 0X42, 0X27, 0X42, 0X07, + 0X62, 0X69, 0X4A, 0X49, 0X42, 0X28, 0X4A, 0X06, 0X4A, 0X27, 0X52, 0X69, + 0X4A, 0X27, 0X4A, 0X28, 0X4A, 0X49, 0X52, 0X27, 0X4A, 0X28, 0X4A, 0X28, + 0X52, 0X49, 0X39, 0XC6, 0X41, 0XE7, 0X42, 0X28, 0X39, 0XE7, 0X3A, 0X08, + 0X41, 0XE7, 0X41, 0XC6, 0X41, 0XC6, 0X39, 0XC6, 0X41, 0XC6, 0X4A, 0X28, + 0X39, 0XC6, 0X41, 0XE7, 0X42, 0X28, 0X42, 0X28, 0X42, 0X07, 0X42, 0X29, + 0X42, 0X29, 0X42, 0X49, 0X4A, 0X6A, 0X4A, 0X6A, 0X4A, 0X6A, 0X4A, 0X28, + 0X52, 0X29, 0X5A, 0X69, 0X5A, 0X48, 0X5A, 0X48, 0X4A, 0X27, 0X4A, 0X29, + 0X42, 0X07, 0X3A, 0X08, 0X39, 0XC6, 0X41, 0XA5, 0X39, 0XA5, 0X39, 0XA5, + 0X42, 0X07, 0X4A, 0X28, 0X42, 0X07, 0X42, 0X07, 0X4A, 0X28, 0X4A, 0X27, + 0X42, 0X28, 0X42, 0X28, 0X42, 0X07, 0X42, 0X07, 0X42, 0X28, 0X4A, 0X07, + 0X52, 0X27, 0X4A, 0X48, 0X11, 0X46, 0X3A, 0X8B, 0X7C, 0XB3, 0X74, 0X72, + 0X7C, 0X93, 0X73, 0XCF, 0X4A, 0X48, 0X3A, 0X08, 0X42, 0X48, 0X42, 0X28, + 0X3A, 0X28, 0X42, 0X28, 0X3A, 0X28, 0X3A, 0X28, 0X3A, 0X07, 0X31, 0XE7, + 0X42, 0X48, 0X4A, 0X69, 0X42, 0X48, 0X42, 0X28, 0X4A, 0X48, 0X4A, 0X49, + 0X4A, 0X69, 0X42, 0X28, 0X39, 0XE7, 0X42, 0X28, 0X42, 0X48, 0X29, 0X86, + 0X21, 0X86, 0X21, 0XA8, 0X39, 0XE7, 0X42, 0X07, 0X39, 0XE7, 0X31, 0XE7, + 0X32, 0X08, 0X31, 0XE7, 0X31, 0XE8, 0X21, 0XCA, 0X19, 0XCA, 0X19, 0XCB, + 0X1A, 0X2C, 0X22, 0X6C, 0X2A, 0XAC, 0X2A, 0XCC, 0X2A, 0XAC, 0X2A, 0XAB, + 0X2A, 0XCC, 0X2A, 0XCC, 0X2A, 0XEC, 0X3B, 0X0B, 0X3A, 0XEC, 0X43, 0X2D, + 0X21, 0X86, 0X1B, 0X4A, 0X2C, 0X0D, 0X23, 0XAD, 0X2C, 0X10, 0X34, 0X51, + 0X3B, 0X8F, 0X43, 0X6E, 0X53, 0XEF, 0X5C, 0X2F, 0X63, 0XED, 0X73, 0X8A, + 0X52, 0XA7, 0X5A, 0XA9, 0X62, 0XC9, 0X52, 0XCA, 0X43, 0X6E, 0X54, 0X0F, + 0X4C, 0X30, 0X44, 0X10, 0X3C, 0X11, 0X3C, 0X10, 0X44, 0X10, 0X44, 0X0F, + 0X4B, 0XEF, 0X4B, 0XCF, 0X5B, 0XAE, 0X5B, 0X6D, 0X5B, 0X6D, 0X5B, 0X4B, + 0X53, 0X0A, 0X53, 0X2B, 0X5B, 0X48, 0X5B, 0X25, 0X83, 0XC6, 0X7B, 0X66, + 0X73, 0X67, 0X7B, 0XA7, 0X73, 0X87, 0X7B, 0XA7, 0X73, 0X86, 0X7B, 0XA7, + 0X73, 0X87, 0X6B, 0X2B, 0X6B, 0X0B, 0X7B, 0X6D, 0X83, 0X6F, 0X73, 0X4F, + 0X5B, 0X0E, 0X5B, 0X0E, 0X5B, 0X0E, 0X5B, 0X0E, 0X5B, 0X0D, 0X53, 0X0D, + 0X4A, 0XED, 0X4A, 0XCB, 0X52, 0XEB, 0X53, 0X0B, 0X42, 0XAA, 0X42, 0XAB, + 0X42, 0XCB, 0X53, 0X0B, 0X52, 0XCB, 0X4A, 0XAB, 0X42, 0X8C, 0X3A, 0X8C, + 0X22, 0XCC, 0X3B, 0X29, 0X3A, 0XCC, 0X4B, 0X0C, 0X42, 0XEC, 0X1A, 0XAB, + 0X22, 0XAD, 0X2A, 0XAE, 0X1A, 0XAE, 0X1A, 0XCD, 0X32, 0X2A, 0X31, 0XE8, + 0X3A, 0X29, 0X3A, 0X49, 0X42, 0X69, 0X4A, 0X8A, 0X4A, 0XAA, 0X6B, 0XAE, + 0X73, 0XF0, 0X6B, 0XAE, 0X5A, 0XEB, 0X52, 0XCB, 0X63, 0X8E, 0X74, 0X11, + 0X7C, 0X31, 0X6B, 0XCF, 0X53, 0X4D, 0X53, 0X6E, 0X4B, 0X0C, 0X42, 0X49, + 0X4A, 0XAA, 0X4B, 0X0B, 0X4A, 0XCA, 0X42, 0XA9, 0X52, 0XEB, 0X52, 0XEB, + 0X42, 0XCA, 0X42, 0XCA, 0X4A, 0XEA, 0X4A, 0XEA, 0X42, 0XEB, 0X3A, 0XCB, + 0X3A, 0XCB, 0X3A, 0XEC, 0X3A, 0XAA, 0X32, 0X69, 0X32, 0XEC, 0X32, 0XEC, + 0X32, 0XED, 0X3A, 0XCC, 0X4A, 0XEC, 0X43, 0X90, 0X43, 0X4E, 0X43, 0X2D, + 0X43, 0X90, 0X4B, 0XB0, 0X5B, 0X8E, 0X6B, 0XCF, 0X63, 0XAF, 0X8C, 0XB2, + 0X95, 0X14, 0X6B, 0XF0, 0X4B, 0X0B, 0X32, 0X69, 0X42, 0XCB, 0X3A, 0XEC, + 0X3A, 0XCC, 0X42, 0XEE, 0X3A, 0XEE, 0X42, 0XEE, 0X4B, 0X2E, 0X4B, 0X2E, + 0X4B, 0X4F, 0X43, 0X0D, 0X8C, 0X72, 0X7C, 0XB4, 0X85, 0X15, 0X7C, 0XF5, + 0X7D, 0X16, 0X93, 0X08, 0X92, 0X85, 0X6C, 0X32, 0X65, 0X17, 0X6C, 0X10, + 0X63, 0X8D, 0X73, 0XAD, 0X6C, 0X93, 0X62, 0X04, 0X7B, 0X8C, 0X84, 0X50, + 0X8B, 0X0A, 0X82, 0X87, 0X4A, 0X8A, 0X51, 0X43, 0X5B, 0XAC, 0X64, 0X50, + 0X64, 0X93, 0X6B, 0XF0, 0X6B, 0X28, 0X6B, 0X8A, 0X54, 0XD3, 0X6D, 0X13, + 0X7B, 0XAC, 0X73, 0X8B, 0X8B, 0X69, 0X63, 0XCE, 0X5C, 0XD3, 0X74, 0X50, + 0X73, 0XEF, 0X6A, 0X88, 0X62, 0X87, 0X73, 0XCF, 0X74, 0X31, 0X72, 0XE9, + 0X73, 0X2A, 0X6B, 0XEE, 0X63, 0X8D, 0X7B, 0XAD, 0X7C, 0X0F, 0X74, 0X51, + 0X84, 0XB2, 0X7C, 0X72, 0X8B, 0X8B, 0X83, 0XEE, 0X6B, 0X2A, 0X62, 0X66, + 0X6A, 0XC8, 0X83, 0XEE, 0X83, 0XEE, 0X84, 0X50, 0X74, 0XB4, 0X7C, 0X71, + 0X83, 0XEE, 0X83, 0XEE, 0X7C, 0X0F, 0X74, 0XB2, 0X7C, 0XF4, 0X74, 0X10, + 0X63, 0X2C, 0X7B, 0XCE, 0X7C, 0X0E, 0X7C, 0X50, 0X8D, 0X75, 0X85, 0X14, + 0X74, 0X51, 0X7B, 0XAD, 0X83, 0X8C, 0X73, 0X6C, 0X59, 0X83, 0X62, 0X67, + 0X6C, 0X72, 0X74, 0X71, 0X84, 0XD3, 0X74, 0X50, 0X74, 0XD4, 0X74, 0X51, + 0X72, 0X24, 0X83, 0XAD, 0X8B, 0X8C, 0X83, 0XCE, 0X83, 0XEF, 0X51, 0XE5, + 0X63, 0X2C, 0X63, 0X4C, 0X73, 0XCE, 0X41, 0X44, 0X30, 0XC1, 0X39, 0X64, + 0X6B, 0X6B, 0X82, 0XA4, 0X82, 0X65, 0X6A, 0X65, 0X6B, 0XCE, 0X63, 0XCF, + 0X6B, 0XAE, 0X73, 0XEE, 0X82, 0X44, 0X7B, 0X49, 0X7A, 0X86, 0X8A, 0X87, + 0X8B, 0X4B, 0X73, 0XCE, 0X73, 0XAD, 0X83, 0X4B, 0X73, 0X4B, 0X6B, 0X6B, + 0X6B, 0X6B, 0X73, 0X6A, 0X73, 0X8C, 0X5B, 0XCF, 0X5C, 0XB4, 0X73, 0XEE, + 0X73, 0X29, 0X73, 0XAD, 0X74, 0X0F, 0X74, 0X0F, 0X74, 0XB3, 0X6C, 0XD4, + 0X74, 0X92, 0X84, 0X0E, 0X7C, 0XD2, 0X4B, 0X4D, 0X3A, 0XEC, 0X5A, 0XE9, + 0X83, 0XCD, 0X43, 0X6F, 0X5B, 0X6E, 0X83, 0XEF, 0X73, 0XCE, 0X73, 0XCE, + 0X7B, 0XCE, 0X93, 0XCE, 0X93, 0XCD, 0X83, 0XAD, 0X63, 0XF0, 0X5C, 0XB5, + 0X54, 0XD6, 0X7B, 0X6A, 0X73, 0XEE, 0X5D, 0X17, 0X7B, 0X69, 0X8A, 0XA3, + 0X8A, 0XA3, 0X7B, 0X08, 0X4B, 0XF2, 0X5A, 0XC9, 0X5A, 0XA8, 0X62, 0XC9, + 0X7B, 0XAE, 0X6B, 0XCE, 0X8B, 0XCF, 0X83, 0XCF, 0X83, 0XCF, 0X83, 0X8A, + 0X73, 0XAA, 0X6A, 0X65, 0X69, 0XC4, 0X74, 0X10, 0X95, 0X58, 0XB4, 0XD4, + 0XB4, 0X70, 0X9B, 0X8C, 0X6B, 0X6C, 0X83, 0X8C, 0X9B, 0X8D, 0X8B, 0X4B, + 0X8B, 0X0B, 0X82, 0XCA, 0X83, 0X2C, 0X93, 0X6D, 0X93, 0X4C, 0X93, 0X4C, + 0X93, 0X6C, 0X8B, 0X4C, 0X8A, 0XEB, 0X9C, 0X31, 0X8B, 0X8E, 0X93, 0XD0, + 0XAC, 0XB4, 0X93, 0XAE, 0X8B, 0X2C, 0X8B, 0X8E, 0X9C, 0X31, 0X83, 0X0B, + 0X93, 0X8E, 0XAC, 0X51, 0X9B, 0X4C, 0X8A, 0XEA, 0XA4, 0X30, 0X9C, 0X74, + 0XAC, 0XAF, 0X82, 0XC5, 0X51, 0X42, 0X6A, 0X24, 0X7B, 0X07, 0X6A, 0X24, + 0X61, 0XE3, 0X72, 0XA6, 0X83, 0X48, 0X8B, 0XC9, 0X62, 0X66, 0X6A, 0X65, + 0X6A, 0X86, 0X72, 0XC7, 0X7B, 0X28, 0X83, 0X48, 0X82, 0XE7, 0X61, 0XA3, + 0X61, 0XA3, 0X82, 0XE8, 0X7A, 0XA7, 0X8B, 0X4A, 0X83, 0X4B, 0X6A, 0X47, + 0X72, 0X26, 0X69, 0XE4, 0X7A, 0X66, 0X9C, 0X2C, 0X9C, 0X0C, 0X9C, 0X2C, + 0XA4, 0X6D, 0XAC, 0X6E, 0XB4, 0X4C, 0XA3, 0XAA, 0X82, 0XE8, 0X72, 0X88, + 0X62, 0X05, 0X49, 0X44, 0X41, 0X24, 0X6A, 0X68, 0X82, 0XE9, 0X9B, 0X69, + 0X59, 0XC6, 0X40, 0XE4, 0X6A, 0X68, 0XB4, 0XAE, 0X72, 0X25, 0X8B, 0X29, + 0X8B, 0X4A, 0X93, 0X08, 0XA3, 0X89, 0XA4, 0X4D, 0X72, 0XC9, 0X49, 0X44, + 0X83, 0X09, 0X72, 0X88, 0X72, 0X87, 0X7A, 0XA8, 0X7B, 0X4B, 0X7A, 0XA8, + 0X72, 0X46, 0X72, 0X87, 0X7A, 0XA8, 0X82, 0XE8, 0X72, 0X88, 0X5A, 0X06, + 0X6A, 0X25, 0X59, 0XE4, 0X61, 0XE4, 0X49, 0X63, 0X28, 0XC1, 0X41, 0X23, + 0X4A, 0X27, 0X5A, 0XC9, 0X5A, 0XA8, 0X51, 0XC5, 0X51, 0X84, 0X6A, 0X67, + 0X69, 0XE5, 0X62, 0XE8, 0X49, 0X63, 0X38, 0XE2, 0X42, 0X68, 0X5A, 0X26, + 0X61, 0XA3, 0X40, 0XE2, 0X51, 0X23, 0X49, 0X22, 0X49, 0X02, 0X49, 0X02, + 0X41, 0X23, 0X49, 0XA5, 0X41, 0X02, 0X41, 0X43, 0X6A, 0X25, 0X59, 0XA4, + 0X41, 0X23, 0X49, 0X23, 0X49, 0X63, 0X7A, 0XA7, 0X72, 0XA7, 0X7A, 0XA8, + 0X72, 0X46, 0X72, 0X67, 0X7A, 0X86, 0X72, 0XA7, 0X72, 0X86, 0X7A, 0X86, + 0X92, 0XE7, 0X82, 0X86, 0X7A, 0XA6, 0X82, 0X86, 0X8A, 0XC7, 0XA4, 0X6D, + 0XA3, 0X89, 0X7A, 0XE8, 0X7A, 0X87, 0X8B, 0X09, 0X93, 0X6A, 0XA4, 0X8E, + 0XA4, 0X8D, 0XA3, 0X8A, 0XAB, 0X28, 0XAB, 0X29, 0XAB, 0X69, 0X93, 0XAA, + 0X8B, 0X49, 0X93, 0X49, 0X82, 0XC8, 0X6B, 0X09, 0X31, 0X23, 0X28, 0XE2, + 0X30, 0XC3, 0X49, 0XC5, 0X41, 0XC4, 0X31, 0X22, 0X28, 0XC1, 0X41, 0X62, + 0X59, 0XE3, 0X49, 0X83, 0X6B, 0X49, 0X93, 0XCA, 0X7B, 0X8A, 0X6B, 0X09, + 0X83, 0XEC, 0X83, 0X6A, 0X83, 0X29, 0X83, 0X29, 0X83, 0X4A, 0X7B, 0X4A, + 0X5A, 0X27, 0X6A, 0X67, 0X7B, 0X6B, 0X94, 0X6E, 0X94, 0X2D, 0X6B, 0X2A, + 0X61, 0XA6, 0X59, 0X64, 0X69, 0XC6, 0X62, 0XA8, 0X7A, 0X87, 0X92, 0XA7, + 0X82, 0XC7, 0X8A, 0XC8, 0X7A, 0X67, 0X82, 0X87, 0X7A, 0X87, 0X7A, 0XA8, + 0X93, 0XAB, 0X7B, 0X6B, 0X73, 0X4A, 0X62, 0X66, 0X6A, 0X86, 0X6A, 0X86, + 0X6A, 0XA7, 0X82, 0XE7, 0X7A, 0XE7, 0X7A, 0XC6, 0X8B, 0X8A, 0X9B, 0X69, + 0X8B, 0XCB, 0X93, 0XCB, 0X82, 0XC8, 0X93, 0X8A, 0X8B, 0XAB, 0X93, 0XEB, + 0X94, 0X2C, 0X92, 0X85, 0X8A, 0X44, 0X82, 0X25, 0X72, 0X46, 0X41, 0X86, + 0X62, 0X27, 0X8B, 0X29, 0X72, 0X45, 0X82, 0XE8, 0X93, 0X4A, 0X61, 0XE5, + 0X72, 0X66, 0X93, 0X49, 0X72, 0X67, 0X6A, 0X67, 0X93, 0X8A, 0X8B, 0X8B, + 0X83, 0X29, 0X82, 0X66, 0X62, 0X06, 0X7A, 0X67, 0X82, 0XA7, 0X82, 0X87, + 0X82, 0XA8, 0X7B, 0X08, 0X72, 0X66, 0X5A, 0X67, 0XA4, 0X8E, 0X93, 0X8B, + 0X72, 0X25, 0X59, 0XC4, 0X72, 0X87, 0X9C, 0X4D, 0X94, 0X4D, 0X94, 0X2C, + 0X93, 0XEC, 0X8B, 0X8B, 0X72, 0X25, 0X94, 0X0B, 0X5A, 0X25, 0X41, 0X63, + 0X51, 0XC4, 0X72, 0X86, 0X72, 0XA8, 0X83, 0X09, 0X59, 0XA4, 0X59, 0XE5, + 0X83, 0XAA, 0X83, 0X29, 0X8B, 0X09, 0X8B, 0X08, 0X93, 0X08, 0X5A, 0X29, + 0X7B, 0X2A, 0X7A, 0XE9, 0X62, 0X27, 0X8B, 0X29, 0X9B, 0X8A, 0X93, 0X09, + 0X92, 0XA7, 0X8A, 0X26, 0X89, 0XE5, 0X89, 0XE5, 0X81, 0XE4, 0X81, 0XE4, + 0X92, 0X05, 0X9A, 0X05, 0X79, 0X64, 0X61, 0X03, 0X61, 0X63, 0X69, 0X43, + 0X81, 0X44, 0X71, 0X44, 0X51, 0X45, 0X38, 0XC3, 0X38, 0XC3, 0X40, 0XE3, + 0X51, 0X65, 0X38, 0XE2, 0X38, 0XC1, 0X81, 0XC5, 0X48, 0XE4, 0X79, 0XA4, + 0X61, 0X43, 0X48, 0XE3, 0X50, 0XE3, 0X61, 0X24, 0X8A, 0XEE, 0X83, 0X0D, + 0XA1, 0XED, 0X81, 0X4B, 0X61, 0X23, 0X61, 0X45, 0X59, 0X25, 0X50, 0XE4, + 0X41, 0X03, 0X51, 0X03, 0X39, 0X04, 0X21, 0X26, 0X21, 0X06, 0X21, 0X06, + 0X21, 0X68, 0X29, 0X89, 0X29, 0X89, 0X20, 0XE5, 0X20, 0XE4, 0X21, 0X05, + 0X19, 0X05, 0X21, 0X26, 0X19, 0X26, 0X29, 0XCA, 0X29, 0X89, 0X21, 0X47, + 0X21, 0X47, 0X21, 0X26, 0X21, 0X68, 0X29, 0XA9, 0X21, 0X88, 0X21, 0X67, + 0X32, 0X4C, 0X29, 0XEA, 0X21, 0X88, 0X21, 0X89, 0X21, 0X88, 0X21, 0X88, + 0X21, 0X89, 0X21, 0X47, 0X29, 0X05, 0X21, 0X05, 0X21, 0X47, 0X19, 0X26, + 0X19, 0X47, 0X21, 0X88, 0X19, 0X46, 0X19, 0X46, 0X21, 0X67, 0X19, 0X05, + 0X19, 0X05, 0X19, 0X05, 0X19, 0X05, 0X19, 0X05, 0X19, 0X46, 0X19, 0X88, + 0X19, 0X68, 0X19, 0X26, 0X19, 0X47, 0X21, 0XC9, 0X19, 0XA9, 0X10, 0XC4, + 0X10, 0X41, 0X18, 0XC4, 0X19, 0X47, 0X21, 0XA9, 0X21, 0X25, 0X18, 0XE5, + 0X19, 0X05, 0X19, 0X26, 0X19, 0X26, 0X11, 0X26, 0X19, 0X47, 0X18, 0XE5, + 0X19, 0X47, 0X19, 0X47, 0X18, 0XC5, 0X19, 0X27, 0X19, 0X68, 0X21, 0X67, + 0X42, 0X4B, 0X59, 0XA8, 0XB9, 0XA7, 0X81, 0XA9, 0X71, 0XAA, 0X32, 0X6A, + 0X32, 0X07, 0X48, 0XE7, 0X39, 0X8B, 0X3A, 0XA9, 0X3A, 0X26, 0X81, 0X64, + 0X91, 0X05, 0X78, 0XEA, 0X59, 0X6D, 0X72, 0X2B, 0X91, 0X85, 0X89, 0X45, + 0X81, 0X65, 0X7A, 0XE7, 0X18, 0XE2, 0X08, 0X41, 0X30, 0XC2, 0X18, 0X61, + 0X10, 0XA1, 0X38, 0XC4, 0X68, 0XE4, 0X40, 0X83, 0X18, 0X61, 0X18, 0X61, + 0X59, 0X87, 0X31, 0X2B, 0X50, 0XA7, 0X61, 0X07, 0X9A, 0X45, 0X9A, 0X64, + 0X71, 0XE6, 0X6A, 0X85, 0X1A, 0X6B, 0X21, 0X26, 0X79, 0X28, 0X81, 0X49, + 0X61, 0X2A, 0X50, 0XE8, 0X69, 0X07, 0X60, 0X84, 0X51, 0X08, 0X39, 0XAA, + 0X61, 0XC2, 0X81, 0XC3, 0X29, 0XAB, 0X31, 0XAA, 0X20, 0XE3, 0X20, 0XC3, + 0X20, 0XC1, 0X18, 0X61, 0X10, 0X62, 0X29, 0X66, 0X31, 0X87, 0X31, 0XE9, + 0X20, 0XE3, 0X18, 0XA2, 0X18, 0XC2, 0X18, 0XC2, 0X18, 0XC2, 0X18, 0XC3, + 0X18, 0XA2, 0X10, 0X81, 0X18, 0XC2, 0X20, 0XC2, 0X18, 0XC2, 0X18, 0XC2, + 0X20, 0XE2, 0X28, 0XE3, 0X18, 0XA2, 0X18, 0XA2, 0X20, 0XA1, 0X29, 0X47, + 0X31, 0X88, 0X29, 0X47, 0X18, 0XA1, 0X21, 0X06, 0X21, 0X26, 0X18, 0XC2, + 0X18, 0XA2, 0X18, 0XA1, 0X18, 0X81, 0X18, 0X81, 0X18, 0XA1, 0X20, 0XC2, + 0X18, 0XC2, 0X20, 0XC1, 0X28, 0XC1, 0X29, 0X02, 0X39, 0X86, 0X39, 0X85, + 0X39, 0XA6, 0X39, 0X85, 0X20, 0XA1, 0X29, 0X24, 0X29, 0X03, 0X20, 0XC1, + 0X49, 0XC5, 0X39, 0X84, 0X29, 0X23, 0X31, 0X43, 0X29, 0X43, 0X31, 0X64, + 0X5A, 0XC9, 0X5A, 0XAA, 0X63, 0X2B, 0X52, 0X26, 0X52, 0X68, 0X49, 0XE4, + 0X4A, 0X26, 0X52, 0X88, 0X5A, 0XCA, 0X63, 0X2C, 0X63, 0X2B, 0X31, 0X64, + 0X20, 0XE2, 0X31, 0X64, 0X62, 0XE9, 0X5A, 0XA9, 0X52, 0X88, 0X5A, 0XC9, + 0X6B, 0X2B, 0X52, 0XA9, 0X52, 0X89, 0X5A, 0XA9, 0X5A, 0XA9, 0X5A, 0XAA, + 0X73, 0X8C, 0X84, 0X0D, 0X63, 0X0A, 0X52, 0XA9, 0X5A, 0XC9, 0X41, 0XC5, + 0X52, 0X89, 0X4A, 0X28, 0X41, 0X84, 0X41, 0X84, 0X31, 0X24, 0X83, 0X05, + 0XC4, 0XC8, 0X9B, 0XA7, 0X82, 0XA4, 0X49, 0X83, 0X62, 0X86, 0X52, 0X04, + 0X39, 0X63, 0X6A, 0XA6, 0X49, 0XC5, 0X52, 0X05, 0X6A, 0XC7, 0X41, 0XC4, + 0X72, 0XC5, 0X7A, 0XE5, 0X83, 0X06, 0X6A, 0X88, 0X29, 0X04, 0X10, 0X62, + 0X28, 0XA2, 0X20, 0X82, 0X38, 0XC2, 0X18, 0XA4, 0X20, 0XA2, 0X38, 0XE3, + 0X49, 0X03, 0X49, 0X03, 0X49, 0X23, 0X31, 0X04, 0X18, 0XA3, 0X28, 0XA2, + 0X28, 0XA2, 0X30, 0XE3, 0X39, 0X24, 0X39, 0X24, 0X31, 0X24, 0X18, 0XA3, + 0X18, 0XA4, 0X31, 0X05, 0X31, 0X05, 0X31, 0X25, 0X31, 0X25, 0X30, 0XC4, + 0X49, 0X44, 0X41, 0X43, 0X20, 0XA3, 0X39, 0X03, 0X61, 0XC5, 0X92, 0XA6, + 0X6A, 0X24, 0X51, 0X83, 0X39, 0X24, 0X39, 0X25, 0X39, 0X04, 0X51, 0X64, + 0X49, 0X44, 0X20, 0X83, 0X41, 0X24, 0X59, 0X04, 0X20, 0X83, 0X20, 0XA3, + 0X51, 0X24, 0X59, 0XA5, 0X39, 0X24, 0X51, 0X84, 0X51, 0X85, 0X31, 0X06, + 0X51, 0X65, 0X61, 0XC5, 0X49, 0X24, 0X69, 0XE4, 0X82, 0X84, 0X49, 0X44, + 0X59, 0X83, 0X72, 0X24, 0X61, 0XC5, 0X59, 0XC5, 0X59, 0XC4, 0X61, 0XC4, + 0X61, 0XE5, 0X61, 0XC4, 0X61, 0XA3, 0X59, 0XA3, 0X61, 0XA4, 0X49, 0X64, + 0X31, 0X04, 0X49, 0X23, 0X30, 0XE3, 0X28, 0XE3, 0X31, 0X04, 0X39, 0X25, + 0X39, 0X24, 0XAB, 0X6A, 0X62, 0X27, 0X49, 0X22, 0X6B, 0X4C, 0X6B, 0X4D, + 0X5A, 0XAA, 0X52, 0X89, 0X62, 0XEB, 0X62, 0X68, 0X6A, 0X89, 0X5A, 0X27, + 0X6A, 0X69, 0X6A, 0X89, 0X6A, 0XCB, 0X6A, 0XCB, 0X62, 0XAA, 0X62, 0XEA, + 0X62, 0XEB, 0X62, 0XAA, 0X6B, 0X2C, 0X6B, 0X6D, 0X62, 0XCA, 0X62, 0XA9, + 0X6A, 0XAA, 0X6A, 0X8A, 0X62, 0XCA, 0X7B, 0X6D, 0X7B, 0X4D, 0X6A, 0XA9, + 0X6A, 0XCB, 0X62, 0XCB, 0X5A, 0XAB, 0X6B, 0X2D, 0X6B, 0X2D, 0X5A, 0XCB, + 0X63, 0X2C, 0X63, 0X0B, 0X5A, 0X8A, 0X5A, 0X8A, 0X5A, 0X8A, 0X5A, 0X6A, + 0X5A, 0X89, 0X5A, 0X47, 0X62, 0X88, 0X6A, 0XCB, 0X62, 0XAA, 0X4A, 0X28, + 0X42, 0X28, 0X4A, 0X28, 0X5A, 0X8A, 0X6A, 0XEB, 0X5A, 0XCB, 0X62, 0XCB, + 0X6B, 0X2C, 0X5A, 0X49, 0X51, 0X65, 0X4A, 0X49, 0X4A, 0X8A, 0X83, 0X4B, + 0X93, 0X6A, 0X7B, 0X29, 0X7B, 0X29, 0X7B, 0X4A, 0X72, 0XE9, 0X7B, 0X09, + 0X7B, 0X4A, 0X8B, 0X4A, 0X83, 0X09, 0X7A, 0XC9, 0X8A, 0XC9, 0X8A, 0XE9, + 0X8B, 0X6B, 0X82, 0XE9, 0X6A, 0X26, 0X61, 0X64, 0X6A, 0X27, 0X72, 0X88, + 0X72, 0XA8, 0X62, 0X07, 0X51, 0X85, 0X41, 0X86, 0X31, 0X25, 0X29, 0X45, + 0X31, 0X65, 0X29, 0X25, 0X21, 0X04, 0X39, 0XA7, 0X5A, 0XAA, 0X29, 0X04, + 0X18, 0XC3, 0X18, 0XC3, 0X29, 0X25, 0X39, 0XA7, 0X29, 0X45, 0X18, 0XE3, + 0X18, 0XC3, 0X41, 0XE8, 0X21, 0X04, 0X08, 0X41, 0X21, 0X04, 0X29, 0X66, + 0X21, 0X04, 0X21, 0X04, 0X20, 0XE4, 0X21, 0X04, 0X29, 0X04, 0X10, 0X82, + 0X18, 0XC3, 0X21, 0X25, 0X20, 0XE4, 0X20, 0XE4, 0X29, 0X24, 0X29, 0X24, + 0X29, 0X24, 0X18, 0XA3, 0X21, 0X04, 0X29, 0X24, 0X10, 0X61, 0X21, 0X04, + 0X08, 0X41, 0X10, 0X61, 0X18, 0XC3, 0X18, 0X82, 0X18, 0XC2, 0X08, 0X41, + 0X18, 0XC2, 0X10, 0X81, 0X10, 0X61, 0X20, 0XC3, 0X18, 0X82, 0X08, 0X41, + 0X08, 0X61, 0X18, 0XA2, 0X20, 0XC3, 0X20, 0XE3, 0X20, 0XE3, 0X18, 0XC2, + 0X18, 0XA2, 0X18, 0XA2, 0X10, 0X61, 0X18, 0X81, 0X18, 0XA2, 0X18, 0XA2, + 0X20, 0XC2, 0X29, 0X24, 0X31, 0X66, 0X31, 0X86, 0X21, 0X04, 0X20, 0XE4, + 0X18, 0XC3, 0X10, 0XA3, 0X18, 0XA4, 0X18, 0XA4, 0X18, 0XC4, 0X20, 0XC4, + 0X18, 0XE5, 0X10, 0XA4, 0X10, 0X83, 0X18, 0XC4, 0X21, 0X06, 0X20, 0XE4, + 0X21, 0X05, 0X20, 0XE5, 0X10, 0XA3, 0X18, 0X82, 0X41, 0X64, 0X29, 0X03, + 0X18, 0XA2, 0X20, 0XC3, 0X18, 0XA2, 0X18, 0XC3, 0X28, 0XE3, 0X29, 0X04, + 0X21, 0X25, 0X29, 0X25, 0X29, 0X45, 0X29, 0X04, 0X18, 0XA2, 0X20, 0XE3, + 0X31, 0X45, 0X18, 0XC3, 0X21, 0X24, 0X29, 0X45, 0X18, 0XE4, 0X18, 0XC4, + 0X20, 0XE3, 0X18, 0XC2, 0X29, 0X44, 0X31, 0X45, 0X18, 0XC4, 0X21, 0X05, + 0X18, 0XC3, 0X18, 0XC3, 0X20, 0XE4, 0X20, 0XE4, 0X20, 0XE3, 0X31, 0X66, + 0X39, 0X86, 0X21, 0X04, 0X18, 0XC3, 0X18, 0XA2, 0X18, 0XA3, 0X21, 0X04, + 0X29, 0X66, 0X29, 0X66, 0X31, 0X87, 0X10, 0XA3, 0X00, 0X00, 0X20, 0X40, + 0X79, 0XE4, 0XAB, 0X68, 0X92, 0XE7, 0X39, 0X23, 0X41, 0X43, 0X41, 0X23, + 0X79, 0XC4, 0X8A, 0X25, 0X82, 0X25, 0X82, 0X25, 0X82, 0X05, 0X8A, 0X05, + 0X89, 0XE5, 0X79, 0X83, 0X89, 0XC4, 0X9A, 0X25, 0X79, 0X83, 0X81, 0XA3, + 0X79, 0X83, 0X81, 0XC4, 0X89, 0XE5, 0X89, 0XE5, 0X69, 0X85, 0X71, 0XC5, + 0X61, 0X84, 0X82, 0X6A, 0X82, 0XAC, 0X59, 0X44, 0X61, 0XA6, 0X59, 0X85, + 0X71, 0XE6, 0X79, 0XC6, 0X69, 0X85, 0X81, 0XE5, 0X82, 0X05, 0X82, 0X27, + 0X8A, 0X69, 0X92, 0X68, 0XA2, 0X86, 0X92, 0X68, 0X8A, 0X47, 0X81, 0XE5, + 0X9A, 0X66, 0X6B, 0X0A, 0X83, 0X08, 0X8B, 0X27, 0X82, 0XC7, 0X7A, 0XA7, + 0X82, 0XC8, 0X8B, 0X08, 0X8B, 0X08, 0X83, 0X08, 0X83, 0X08, 0X8B, 0X08, + 0X93, 0X28, 0X8B, 0X29, 0X7A, 0XE8, 0X8A, 0XE7, 0X93, 0X28, 0X9B, 0X89, + 0X8A, 0XC7, 0X8A, 0XE7, 0X8B, 0X28, 0X8B, 0X28, 0X8B, 0X08, 0X93, 0X07, + 0X82, 0XA6, 0X82, 0XC7, 0X82, 0XA6, 0X82, 0XA6, 0X8B, 0X28, 0X93, 0X69, + 0X93, 0X48, 0X8A, 0XE7, 0X7A, 0XE8, 0X7B, 0X08, 0X72, 0XA8, 0X7B, 0X09, + 0X7A, 0XE8, 0X82, 0XE8, 0X5A, 0X05, 0X6A, 0X67, 0X83, 0X09, 0X93, 0X49, + 0X7A, 0XC9, 0X7A, 0XE9, 0X8B, 0X29, 0X62, 0X47, 0X62, 0X67, 0X6A, 0X25, + 0X18, 0X62, 0X18, 0X62, 0X10, 0X62, 0X10, 0X42, 0X18, 0X62, 0X18, 0X62, + 0X18, 0X62, 0X20, 0X83, 0X28, 0XA3, 0X28, 0XA4, 0X18, 0X63, 0X18, 0X83, + 0X20, 0X84, 0X18, 0X83, 0X18, 0X83, 0X20, 0X83, 0X18, 0X83, 0X18, 0X62, + 0X39, 0X85, 0X72, 0XE8, 0X72, 0XA7, 0X6A, 0X45, 0X82, 0XE7, 0X8A, 0XE6, + 0X6A, 0X66, 0X8A, 0XC6, 0X7A, 0X66, 0X62, 0X25, 0X51, 0XE6, 0X5A, 0X67, + 0X49, 0XE5, 0X31, 0X44, 0X49, 0XE6, 0X49, 0XE5, 0X6A, 0X45, 0X59, 0XE5, + 0X6A, 0X86, 0X8B, 0X28, 0X8B, 0X28, 0X7A, 0XE7, 0X82, 0XE7, 0X83, 0X08, + 0X8B, 0X49, 0X93, 0X49, 0X93, 0X29, 0X93, 0X29, 0X93, 0X49, 0X93, 0X49, + 0XA3, 0X8A, 0X31, 0X44, 0X42, 0X26, 0XA3, 0X69, 0X8B, 0X29, 0X72, 0XEA, + 0X72, 0XCA, 0X29, 0XE7, 0X1A, 0X47, 0X5A, 0XA9, 0X21, 0XC6, 0X72, 0XA8, + 0X72, 0XA7, 0X8B, 0X09, 0X6A, 0X87, 0X6A, 0X66, 0X62, 0X66, 0X5A, 0X46, + 0X72, 0XC8, 0X5A, 0X45, 0X82, 0XE8, 0X6A, 0X87, 0X52, 0X05, 0X62, 0X46, + 0X5A, 0X46, 0X62, 0X66, 0X82, 0XC7, 0X62, 0X86, 0X5A, 0X26, 0X6A, 0X87, + 0X82, 0XE8, 0X8B, 0X07, 0X7B, 0X08, 0X6A, 0X46, 0X6A, 0XA7, 0X83, 0X09, + 0X5A, 0X67, 0X52, 0X07, 0X49, 0XC6, 0X49, 0XE6, 0X4A, 0X07, 0X52, 0X07, + 0X31, 0X85, 0X62, 0XCA, 0X6B, 0X0A, 0X52, 0X69, 0X52, 0X69, 0X6A, 0XEA, + 0X62, 0XA9, 0X4A, 0X07, 0X52, 0X48, 0X52, 0X69, 0X62, 0XEB, 0X52, 0X48, + 0X5A, 0X69, 0X52, 0X69, 0X4A, 0X48, 0X4A, 0X48, 0X42, 0X07, 0X41, 0XE7, + 0X42, 0X07, 0X4A, 0X27, 0X49, 0XE6, 0X49, 0XE6, 0X5A, 0X49, 0X72, 0XEA, + 0X5A, 0X47, 0X5A, 0X27, 0XB5, 0X34, 0X9C, 0X2F, 0XC5, 0X74, 0X8B, 0X8D, + 0XBD, 0X95, 0X9C, 0X0E, 0X8B, 0XCE, 0XBD, 0X75, 0X72, 0XEA, 0XA4, 0XB2, + 0X7B, 0X2B, 0X6A, 0XA9, 0X49, 0XE6, 0X6A, 0X89, 0X73, 0X0B, 0XA4, 0XD2, + 0X6A, 0X89, 0X6A, 0XA9, 0X6A, 0XA9, 0X6A, 0XA9, 0X6A, 0XA9, 0X6A, 0X88, + 0X6A, 0X88, 0X6A, 0XA9, 0X6A, 0XA8, 0X6A, 0XA9, 0X6A, 0XCA, 0X6A, 0XC9, + 0X7A, 0XEA, 0X7B, 0X2B, 0X7B, 0X2B, 0X7B, 0X2B, 0X7B, 0X2B, 0X7B, 0X0B, + 0X8B, 0XAC, 0X83, 0X6C, 0X72, 0XC9, 0X9C, 0X2D, 0X83, 0X6B, 0X72, 0XA9, + 0X72, 0XEA, 0X8B, 0X8D, 0X93, 0XCE, 0X93, 0XCD, 0X93, 0XCD, 0X93, 0XEE, + 0X9B, 0XEE, 0X9C, 0X0F, 0X9C, 0X2E, 0X8B, 0X6A, 0X8B, 0X4A, 0X8B, 0X4A, + 0X7B, 0X0A, 0X5A, 0X47, 0X73, 0XAF, 0X6B, 0X2D, 0X5A, 0X48, 0X62, 0X68, + 0X6A, 0XA9, 0X73, 0X4C, 0X83, 0XAE, 0X84, 0X11, 0XBD, 0XD8, 0XB6, 0X1B, + 0X43, 0X58, 0XAD, 0X7D, 0X3B, 0X3B, 0X64, 0X18, 0X32, 0X6C, 0X32, 0X8E, + 0X6C, 0X35, 0X7C, 0X53, 0X8C, 0XB2, 0X83, 0XEF, 0X7B, 0XCF, 0X73, 0XCD, + 0X6B, 0XF0, 0X6B, 0XD4, 0X73, 0XB1, 0X63, 0XD3, 0X52, 0XAE, 0X7C, 0X33, + 0X7B, 0XF1, 0X7B, 0XAE, 0X73, 0X8E, 0X73, 0X90, 0X7B, 0XCE, 0X7B, 0XAC, + 0X8C, 0X0E, 0X84, 0X12, 0X83, 0XD0, 0X83, 0X8E, 0X83, 0XAF, 0X7B, 0XD1, + 0X7B, 0XAF, 0X73, 0X8E, 0X8C, 0X30, 0X8C, 0X30, 0X73, 0XAF, 0X83, 0XCE, + 0X8C, 0X0F, 0X8C, 0X10, 0X83, 0XF0, 0X73, 0XF1, 0X7B, 0XF0, 0X84, 0X10, + 0X7B, 0XAD, 0X7B, 0X8F, 0X73, 0X6C, 0X73, 0X8E, 0X8C, 0X0F, 0X6B, 0X50, + 0X5A, 0XEF, 0X6C, 0X4E, 0X3B, 0X6C, 0X63, 0X4D, 0X8C, 0X2E, 0X84, 0X4F, + 0X73, 0X6C, 0X52, 0XEA, 0X43, 0X6A, 0X43, 0XEB, 0X43, 0XEB, 0X44, 0X0B, + 0X44, 0X0B, 0X63, 0XEE, 0X7C, 0X0F, 0X64, 0X2C, 0X73, 0XCD, 0X73, 0XCD, + 0X4B, 0X89, 0X43, 0X68, 0X4B, 0X69, 0X4B, 0X69, 0X43, 0X69, 0X4B, 0X69, + 0X6C, 0X73, 0X74, 0X94, 0X6C, 0XB5, 0X6C, 0X94, 0X64, 0X73, 0X6C, 0XB4, + 0X63, 0X4C, 0X73, 0X4A, 0X73, 0X8C, 0X52, 0X48, 0X62, 0XEA, 0X6B, 0X2B, + 0X6B, 0X2B, 0X6B, 0X2C, 0X5A, 0XA9, 0X63, 0X2B, 0X62, 0XEB, 0X73, 0X6D, + 0X7B, 0X8E, 0X7B, 0X8D, 0X52, 0X8A, 0X63, 0X0B, 0X7B, 0XCE, 0X73, 0X8D, + 0X7B, 0XCE, 0X7B, 0X8E, 0X7B, 0X8D, 0X7B, 0XAE, 0X6B, 0X2C, 0X73, 0X6D, + 0X7B, 0XAE, 0X83, 0XEF, 0X8C, 0X0F, 0X94, 0X50, 0X8C, 0X2F, 0X83, 0X8D, + 0X83, 0X6C, 0X83, 0X8D, 0X83, 0X4C, 0X83, 0X4C, 0X8B, 0XCE, 0X83, 0X6C, + 0X8B, 0XCE, 0X9C, 0X91, 0XA4, 0XF2, 0X9D, 0X14, 0X7B, 0XAE, 0X7B, 0X8D, + 0X94, 0X91, 0X8C, 0X50, 0X7B, 0X6C, 0X94, 0X2F, 0X83, 0XEE, 0X8C, 0X0F, + 0X7B, 0XAD, 0X9C, 0X0E, 0X93, 0XED, 0X73, 0X8D, 0X83, 0XCE, 0X83, 0XCE, + 0X83, 0XCE, 0X73, 0X8D, 0X39, 0XC7, 0X41, 0XE7, 0X41, 0XE6, 0X41, 0XE7, + 0X41, 0XC7, 0X4A, 0X08, 0X52, 0X48, 0X52, 0X28, 0X52, 0X28, 0X52, 0X28, + 0X4A, 0X07, 0X4A, 0X07, 0X4A, 0X07, 0X4A, 0X07, 0X52, 0X27, 0X52, 0X27, + 0X52, 0X27, 0X52, 0X27, 0X39, 0XA6, 0X31, 0X65, 0X31, 0X65, 0X31, 0X65, + 0X31, 0X65, 0X41, 0XE7, 0X41, 0XE7, 0X41, 0XC6, 0X4A, 0X48, 0X4A, 0X07, + 0X39, 0X65, 0X39, 0XA6, 0X31, 0X24, 0X5A, 0X69, 0X83, 0XAE, 0X73, 0X2C, + 0X4A, 0X07, 0X39, 0XA6, 0X42, 0X07, 0X4A, 0X28, 0X4A, 0X28, 0X41, 0XC7, + 0X8B, 0XEE, 0XA4, 0XB1, 0XA4, 0XD2, 0X54, 0X2F, 0X43, 0XED, 0X33, 0X27, + 0X4B, 0X89, 0X53, 0XEA, 0X3B, 0X4B, 0X19, 0XE9, 0X22, 0X08, 0X29, 0XE8, + 0X29, 0XC7, 0X42, 0XCA, 0X19, 0X05, 0X32, 0X29, 0X10, 0XC4, 0X21, 0XA6, + 0X21, 0XA6, 0X21, 0X45, 0X29, 0X65, 0X29, 0X65, 0X29, 0X65, 0X31, 0X65, + 0X21, 0X24, 0X29, 0X86, 0X39, 0XE7, 0X41, 0XE7, 0X39, 0XE7, 0X39, 0XE7, + 0X4A, 0X28, 0X42, 0X08, 0X42, 0X08, 0X41, 0XE7, 0X29, 0XA6, 0X21, 0X66, + 0X10, 0XE4, 0X18, 0XC4, 0X21, 0X66, 0X21, 0XC8, 0X22, 0X48, 0X4B, 0X6C, + 0X53, 0X6D, 0X7C, 0X0C, 0XA5, 0X0F, 0XA4, 0XEE, 0X9C, 0X2B, 0X8B, 0XEA, + 0XBD, 0X0D, 0XA4, 0X8D, 0X8B, 0XAA, 0X9B, 0X8C, 0X8B, 0XEC, 0X39, 0X63, + 0X39, 0XA4, 0X21, 0X03, 0X39, 0X84, 0X31, 0X23, 0X29, 0X24, 0X42, 0X86, + 0X42, 0XA6, 0X4A, 0X86, 0X41, 0XA4, 0X4A, 0X87, 0X42, 0X05, 0X39, 0X84, + 0X29, 0X04, 0X39, 0X84, 0X29, 0X04, 0X20, 0XC3, 0X20, 0XC3, 0X31, 0X64, + 0X29, 0X23, 0X29, 0X23, 0X31, 0X44, 0X29, 0X23, 0X29, 0X23, 0X31, 0X64, + 0X31, 0X44, 0X31, 0X44, 0X39, 0X84, 0X29, 0X44, 0X29, 0X04, 0X29, 0X03, + 0X20, 0XE3, 0X18, 0XA2, 0X29, 0XC3, 0X53, 0X4E, 0X4B, 0X12, 0X4B, 0X12, + 0X42, 0XF3, 0X42, 0XC7, 0X3A, 0XF0, 0X43, 0X14, 0X53, 0X4F, 0X4B, 0X12, + 0X5A, 0XEA, 0X53, 0X68, 0X53, 0X27, 0X5B, 0X6C, 0X63, 0XF7, 0X53, 0XB4, + 0X53, 0XF8, 0X73, 0XF0, 0X7B, 0XEC, 0X93, 0XAB, 0XAB, 0X69, 0XBC, 0X2B, + 0X93, 0X2A, 0X82, 0XEA, 0XAB, 0XCB, 0XD4, 0XAB, 0X93, 0X2A, 0X93, 0X28, + 0X8B, 0X2B, 0X93, 0X29, 0X8A, 0X66, 0X59, 0XE6, 0X19, 0X66, 0X21, 0X86, + 0X19, 0X45, 0X6C, 0X13, 0X74, 0X12, 0X52, 0XEA, 0X5B, 0XCF, 0X6B, 0X4C, + 0X7A, 0XC7, 0X7A, 0XC7, 0X42, 0XEF, 0X7B, 0X4D, 0X9C, 0X93, 0X63, 0XD1, + 0X53, 0XC7, 0X42, 0XE9, 0X5A, 0XCE, 0X94, 0XF1, 0X7C, 0X4E, 0X8B, 0XAA, + 0X7B, 0XEC, 0X83, 0X8A, 0X62, 0XE9, 0X83, 0X49, 0X93, 0XA9, 0X63, 0X4D, + 0X7C, 0X11, 0X8A, 0XC8, 0X52, 0X49, 0X53, 0XCE, 0X74, 0X4E, 0X8B, 0X49, + 0X7B, 0XAA, 0X84, 0X6C, 0X84, 0X6C, 0X83, 0X69, 0X84, 0X0A, 0X84, 0X0B, + 0X83, 0X2B, 0X61, 0XA9, 0X69, 0X69, 0XA2, 0X6D, 0XAA, 0XCF, 0X61, 0X89, + 0X38, 0X84, 0X38, 0XA4, 0X58, 0XC7, 0X71, 0X49, 0X69, 0XC8, 0XA2, 0X4D, + 0X89, 0XEB, 0X79, 0X69, 0X50, 0XE5, 0X61, 0X07, 0X48, 0XC5, 0X50, 0XE6, + 0X38, 0X83, 0X69, 0X67, 0X69, 0XA5, 0X40, 0XA4, 0X51, 0X46, 0X51, 0X66, + 0XA3, 0X89, 0XA3, 0X69, 0X7A, 0X67, 0X9B, 0X28, 0X39, 0X43, 0X20, 0XC2, + 0X72, 0X45, 0X31, 0X03, 0X7A, 0XAA, 0X41, 0X85, 0X39, 0X63, 0X51, 0XE6, + 0X10, 0X81, 0X18, 0X81, 0X6A, 0XAA, 0X39, 0X65, 0X42, 0X28, 0X29, 0X03, + 0X18, 0X81, 0X10, 0X61, 0X62, 0X26, 0X8B, 0X49, 0X8B, 0X48, 0X93, 0X88, + 0X8B, 0X07, 0X7A, 0X85, 0X72, 0X44, 0X61, 0XE3, 0X40, 0XE1, 0X61, 0XC3, + 0X61, 0XE3, 0X61, 0XC3, 0X61, 0XC3, 0X61, 0XC3, 0X61, 0XA3, 0X59, 0XC3, + 0X61, 0XC3, 0X51, 0XA3, 0X41, 0X82, 0X51, 0X82, 0X41, 0X63, 0X6A, 0X45, + 0X6A, 0X45, 0X41, 0X83, 0X41, 0X63, 0X51, 0X83, 0X51, 0X83, 0X49, 0X83, + 0X49, 0XC3, 0X49, 0XC3, 0X49, 0XC3, 0X49, 0XA3, 0X39, 0X63, 0X31, 0X02, + 0X31, 0X42, 0X41, 0X83, 0X49, 0X42, 0X49, 0X63, 0X8B, 0X6B, 0X83, 0X6A, + 0X8B, 0XCD, 0X8B, 0XCD, 0X93, 0XCD, 0X9B, 0XED, 0X9B, 0XED, 0X5A, 0X26, + 0X83, 0X29, 0X62, 0X68, 0X39, 0X64, 0X49, 0XA5, 0X39, 0X64, 0X83, 0X2A, + 0X7B, 0X2A, 0X4A, 0XCA, 0X7B, 0X2A, 0X9B, 0XEB, 0XCD, 0X71, 0XDD, 0XD3, + 0X62, 0XCA, 0X41, 0XC7, 0X5A, 0X28, 0X5A, 0X69, 0X52, 0X48, 0X52, 0X08, + 0X52, 0X28, 0X31, 0XA7, 0X19, 0X47, 0X19, 0X47, 0X21, 0X67, 0X31, 0XA8, + 0X63, 0XB0, 0X84, 0X2D, 0X84, 0X4C, 0X74, 0X0E, 0X83, 0XCC, 0XBB, 0XC8, + 0X29, 0X25, 0X29, 0X46, 0X21, 0X25, 0X21, 0X05, 0X29, 0X65, 0X3A, 0X08, + 0X52, 0XEB, 0X3A, 0X49, 0X42, 0X48, 0X39, 0XE8, 0X4A, 0X49, 0X4A, 0X49, + 0X3A, 0X49, 0X3A, 0X28, 0X31, 0XA6, 0X42, 0X69, 0X4B, 0XF0, 0X43, 0X8F, + 0X32, 0X87, 0X32, 0X65, 0X5A, 0X8A, 0X6B, 0X0D, 0X39, 0X87, 0X41, 0XE8, + 0X29, 0X67, 0X31, 0X66, 0X5A, 0X8A, 0X52, 0X69, 0X52, 0X89, 0X5A, 0X8A, + 0X52, 0X69, 0X3A, 0X07, 0X42, 0X28, 0X4A, 0X28, 0X41, 0XC7, 0X5A, 0X69, + 0X42, 0X49, 0X39, 0XC7, 0X4A, 0X68, 0X42, 0X28, 0X42, 0X27, 0X52, 0X89, + 0X4A, 0XA7, 0X43, 0X6D, 0X4B, 0X91, 0X53, 0XD2, 0X5C, 0X12, 0X43, 0X8D, + 0X3B, 0X2C, 0X2A, 0XAC, 0X32, 0XED, 0X5B, 0X89, 0X73, 0XEC, 0X5B, 0XAF, + 0X53, 0XAE, 0X43, 0X0A, 0X21, 0X86, 0X21, 0XA6, 0X29, 0XA6, 0X21, 0XA6, + 0X42, 0XCB, 0X4A, 0XEB, 0X29, 0XC6, 0X2A, 0X07, 0X2A, 0X07, 0X29, 0XE7, + 0X3A, 0X28, 0X42, 0X47, 0X31, 0XA5, 0X31, 0XA5, 0X29, 0X85, 0X31, 0X64, + 0X41, 0XC5, 0X5A, 0X8A, 0X5A, 0X8A, 0X4A, 0X07, 0X51, 0XE5, 0X6A, 0X64, + 0X6A, 0X44, 0X8B, 0X27, 0X8A, 0XE6, 0X82, 0XC5, 0X8B, 0X48, 0X83, 0X07, + 0X7A, 0X44, 0X72, 0X45, 0X7A, 0XA5, 0X7A, 0XA5, 0X31, 0X22, 0X28, 0XE1, + 0X29, 0X02, 0X29, 0X02, 0X28, 0XE1, 0X29, 0X02, 0X62, 0XE8, 0X6B, 0X29, + 0X6B, 0X27, 0X72, 0XC6, 0X6A, 0X45, 0X7A, 0XC6, 0X7A, 0XC6, 0X7A, 0XC6, + 0X7A, 0XC6, 0X7A, 0XC6, 0X82, 0XE6, 0X72, 0X85, 0X7A, 0X86, 0X7A, 0X65, + 0X73, 0X08, 0X5B, 0X49, 0X6A, 0XC6, 0X6B, 0X07, 0X5A, 0X66, 0X51, 0XE6, + 0X73, 0XEF, 0X73, 0XAD, 0X5A, 0X68, 0X52, 0X48, 0X73, 0XAD, 0X7B, 0XAC, + 0X83, 0X8D, 0X6B, 0X0A, 0X6A, 0XE9, 0X63, 0X4B, 0X73, 0XAD, 0X62, 0XC9, + 0X6A, 0XE9, 0X84, 0X0E, 0X83, 0XAC, 0X5A, 0X46, 0X6B, 0X29, 0X6B, 0X2B, + 0X42, 0X2A, 0X52, 0X49, 0X8A, 0XA4, 0X8A, 0X84, 0X72, 0X86, 0X6A, 0X86, + 0X7A, 0X85, 0X7A, 0XA5, 0X7A, 0XA6, 0X7A, 0X85, 0X5A, 0XA7, 0X7A, 0XC6, + 0X82, 0XA5, 0X8A, 0XA6, 0X8A, 0X85, 0X83, 0X08, 0X72, 0XC7, 0X7A, 0XC6, + 0X72, 0X45, 0X6A, 0X67, 0X11, 0X8F, 0X21, 0XEC, 0X2A, 0X49, 0X32, 0X69, + 0X42, 0XEB, 0X63, 0X69, 0X5B, 0X2A, 0X32, 0X26, 0X29, 0XC5, 0X29, 0XE6, + 0X3A, 0X8B, 0X2A, 0X4C, 0X22, 0X0B, 0X21, 0XEB, 0X42, 0XAA, 0X42, 0XAA, + 0X09, 0X49, 0X19, 0XA8, 0X32, 0X47, 0X32, 0X27, 0X32, 0X27, 0X32, 0X48, + 0X3A, 0X67, 0X32, 0X48, 0X3A, 0X88, 0X3A, 0X67, 0X72, 0X66, 0X51, 0XC4, + 0X39, 0XC4, 0X32, 0X47, 0X2A, 0X47, 0X21, 0X22, 0X29, 0XE6, 0X2A, 0X08, + 0X20, 0XE0, 0X20, 0XE1, 0X20, 0XE0, 0X21, 0X22, 0X29, 0X84, 0X29, 0X63, + 0X21, 0X86, 0X49, 0XC4, 0X8A, 0XA5, 0X92, 0XE7, 0X82, 0XE6, 0X8A, 0XA5, + 0X7A, 0XA5, 0X82, 0X85, 0X82, 0XC6, 0X5A, 0X45, 0X5A, 0X05, 0X7A, 0X45, + 0X8A, 0X85, 0X62, 0X04, 0X72, 0X23, 0X7A, 0X24, 0X72, 0X23, 0X62, 0X03, + 0X6A, 0X04, 0X38, 0XE2, 0X28, 0XC1, 0X31, 0X63, 0X39, 0X64, 0X5A, 0X04, + 0X4A, 0X46, 0X2A, 0XAA, 0X32, 0XAA, 0X2A, 0X8A, 0X32, 0XAA, 0X7B, 0XAC, + 0X53, 0X0B, 0X3A, 0X8A, 0X29, 0XE7, 0X21, 0X86, 0X21, 0XC7, 0X4A, 0XCB, + 0X61, 0XA3, 0X5A, 0X66, 0X72, 0XE8, 0X5A, 0XE8, 0X8A, 0XA6, 0X92, 0X85, + 0X7A, 0XC7, 0X4B, 0X0A, 0X6B, 0X09, 0X6A, 0XE9, 0X82, 0X86, 0X82, 0X45, + 0X49, 0X82, 0X29, 0X82, 0X6A, 0XC8, 0X63, 0X2A, 0X6A, 0X66, 0X6A, 0X24, + 0X72, 0X65, 0X7A, 0X45, 0X83, 0X49, 0X72, 0X46, 0X61, 0XE4, 0X42, 0X27, + 0X41, 0XC6, 0X39, 0X63, 0X62, 0X47, 0X6B, 0X4A, 0X52, 0X67, 0X6B, 0X09, + 0X39, 0X43, 0X7A, 0X45, 0X82, 0X85, 0XBB, 0XC9, 0X9A, 0XC7, 0XAA, 0XC6, + 0XA3, 0X07, 0XBB, 0X68, 0XB3, 0X47, 0XA2, 0X85, 0X8A, 0XC5, 0XAB, 0X66, + 0XA3, 0X46, 0XB3, 0X47, 0X9A, 0XE6, 0X7A, 0X64, 0X6A, 0X24, 0XA3, 0X27, + 0X9B, 0X06, 0XB3, 0X67, 0XB3, 0XA7, 0XBB, 0XE8, 0XB3, 0X27, 0XC3, 0XA9, + 0XA2, 0XE7, 0X7A, 0X26, 0X92, 0X65, 0X72, 0X43, 0X6B, 0X4C, 0X94, 0XB2, + 0X94, 0X91, 0X94, 0X91, 0X94, 0X92, 0X94, 0X91, 0X94, 0XB2, 0X42, 0X26, + 0X73, 0XAE, 0X94, 0XB2, 0X8C, 0X91, 0X8C, 0X91, 0X8C, 0X91, 0X8C, 0X91, + 0X42, 0X26, 0X31, 0XA4, 0X31, 0XA4, 0X42, 0X47, 0X94, 0X92, 0X94, 0X91, + 0X42, 0X07, 0X29, 0X64, 0X4A, 0X48, 0X5A, 0X88, 0X5A, 0X87, 0X5A, 0X87, + 0X41, 0XE6, 0X29, 0X64, 0X31, 0X85, 0X29, 0X64, 0X4A, 0XA9, 0X63, 0X6C, + 0X5B, 0X2B, 0X39, 0XE5, 0X39, 0XE5, 0X39, 0XE5, 0X39, 0XE5, 0X39, 0XC5, + 0X42, 0X67, 0X4A, 0X88, 0X39, 0XC5, 0X31, 0XC5, 0X42, 0X68, 0X52, 0XEA, + 0X52, 0XC9, 0X52, 0XC9, 0X52, 0XEA, 0X42, 0X47, 0X39, 0XC5, 0X3A, 0X05, + 0X4A, 0X88, 0X39, 0XE5, 0X3A, 0X06, 0X52, 0XC9, 0X4A, 0X68, 0X39, 0XE5, + 0X3A, 0X06, 0X52, 0XC9, 0X52, 0XC9, 0X52, 0XC9, 0X42, 0X47, 0X39, 0XC5, + 0X3A, 0X06, 0X4A, 0XA9, 0X52, 0XC9, 0X52, 0XC9, 0X52, 0XC9, 0X52, 0XC9, + 0X4A, 0XA9, 0X52, 0XC9, 0X4A, 0X88, 0X39, 0XE5, 0X39, 0XE5, 0X3A, 0X06, + 0X4A, 0XC9, 0X4A, 0X47, 0X41, 0XE5, 0X4A, 0XA8, 0X52, 0XC9, 0X4A, 0XA9, + 0X4A, 0XA9, 0X4A, 0XA9, 0X52, 0XC9, 0X52, 0XC9, 0X52, 0XC9, 0X52, 0XA9, + 0X4A, 0X06, 0X6B, 0X2A, 0X73, 0XAD, 0X52, 0XC9, 0X52, 0XCA, 0X7B, 0XAB, + 0XA4, 0XCE, 0X94, 0XD0, 0X8C, 0X6E, 0X8C, 0X8E, 0X8C, 0X8E, 0X42, 0X47, + 0X20, 0XE2, 0X31, 0X85, 0X42, 0X68, 0X73, 0XED, 0X9D, 0X33, 0X94, 0XF2, + 0X94, 0XF2, 0X95, 0X12, 0X9C, 0XF0, 0X9C, 0X8D, 0X9C, 0X6D, 0X9C, 0XAF, + 0XB4, 0XEE, 0X8B, 0XCA, 0X73, 0X8A, 0X7B, 0XAA, 0X73, 0X6A, 0X4A, 0X27, + 0X4A, 0X06, 0X4A, 0X07, 0X4A, 0X27, 0X4A, 0X27, 0X4A, 0X07, 0X4A, 0X27, + 0X4A, 0X68, 0X39, 0XE6, 0X21, 0X03, 0X5A, 0XA8, 0X7B, 0X8B, 0X73, 0X4A, + 0X7B, 0X8B, 0X8C, 0X4D, 0X8C, 0X2D, 0X8C, 0X4D, 0X8C, 0X2D, 0X8C, 0X2D, + 0X8C, 0X2D, 0X8C, 0X4D, 0X8C, 0X4D, 0X8C, 0X4E, 0X7B, 0X6B, 0X8C, 0X0E, + 0XAD, 0X74, 0XA5, 0X94, 0XA5, 0X12, 0X8C, 0X2D, 0X8C, 0X2D, 0X8C, 0X4D, + 0X7B, 0X8B, 0X73, 0X2A, 0X73, 0X4A, 0X73, 0X6A, 0X7B, 0X6A, 0X7B, 0X6A, + 0X7B, 0X6A, 0X73, 0X6A, 0X73, 0X6A, 0X8B, 0X8B, 0X83, 0X4A, 0X8B, 0X09, + 0X9A, 0XAA, 0X9A, 0XAA, 0X92, 0XEA, 0X7B, 0X6A, 0X7B, 0X6A, 0X7B, 0X8A, + 0X7B, 0X8A, 0X7B, 0X8A, 0X7B, 0X8B, 0X7B, 0X8B, 0X7B, 0X4A, 0X83, 0X09, + 0X83, 0X2A, 0X7B, 0X0A, 0X83, 0X4A, 0X52, 0X47, 0X4A, 0X47, 0X73, 0XAD, + 0X6B, 0X8D, 0X6B, 0X6C, 0X9D, 0X12, 0X8C, 0XD1, 0X7C, 0X2F, 0X7C, 0X4F, + 0X84, 0X0E, 0X84, 0X70, 0X52, 0X67, 0X7C, 0X2F, 0X7C, 0X2F, 0X5A, 0XC9, + 0X63, 0X2A, 0X63, 0X0A, 0X63, 0X0A, 0X5A, 0XE9, 0X7B, 0XCC, 0X8C, 0X6F, + 0X84, 0X4F, 0X7C, 0X4F, 0X7C, 0X4F, 0X7C, 0X4F, 0X8C, 0XF3, 0X95, 0X55, + 0X8D, 0X34, 0X8D, 0X34, 0XAD, 0X53, 0XAD, 0X32, 0XAC, 0XF1, 0XAD, 0X32, + 0XB5, 0X53, 0XA5, 0X12, 0X84, 0X70, 0X84, 0X70, 0X8C, 0XB1, 0X94, 0XD2, + 0X94, 0XB1, 0X94, 0XD2, 0X94, 0XF1, 0X6B, 0X6B, 0X39, 0XA5, 0X52, 0X88, + 0X94, 0XD1, 0X84, 0X2E, 0X84, 0X4E, 0X84, 0X2E, 0X84, 0X4E, 0X7B, 0XED, + 0X5B, 0X0B, 0X5B, 0X2B, 0X7C, 0X0E, 0X84, 0X0D, 0X7B, 0X89, 0X72, 0XE7, + 0X73, 0X08, 0X73, 0X08, 0X73, 0X08, 0X73, 0X08, 0X73, 0X08, 0X73, 0X08, + 0X73, 0X08, 0X73, 0X08, 0X73, 0X08, 0X73, 0X08, 0X7B, 0X07, 0X5A, 0XA8, + 0X73, 0XAB, 0X94, 0XAE, 0X9D, 0X31, 0XA5, 0X31, 0X94, 0X6D, 0X73, 0X68, + 0X73, 0X88, 0X63, 0X08, 0X8C, 0X0A, 0X9C, 0X8C, 0X94, 0X4C, 0X73, 0X8A, + 0X73, 0X8A, 0X94, 0X4D, 0X94, 0X2D, 0X9C, 0X6E, 0X8B, 0XEB, 0X93, 0X88, + 0X94, 0X6D, 0X94, 0XAF, 0X94, 0X8F, 0X94, 0X8E, 0X94, 0X8F, 0X8C, 0X4D, + 0X7B, 0XAA, 0X73, 0XAA, 0X73, 0XEB, 0X73, 0XCB, 0X84, 0X0C, 0X7B, 0XAB, + 0X84, 0X0D, 0X94, 0XD0, 0X6B, 0X2A, 0X4A, 0X06, 0X83, 0XEE, 0XB5, 0XB5, + 0XAD, 0X74, 0XB5, 0XF6, 0XB5, 0XB5, 0XB5, 0XD5, 0XB5, 0XD5, 0XB5, 0XB5, + 0XB5, 0XD5, 0X9D, 0X13, 0X9D, 0X33, 0XBD, 0XF6, 0XAD, 0X95, 0XB5, 0X94, + 0X9C, 0XCF, 0X8C, 0X6D, 0X84, 0X0C, 0X73, 0X8B, 0X7B, 0X8B, 0X8C, 0X2C, + 0X94, 0X4D, 0X94, 0X4D, 0X94, 0X4D, 0X94, 0X4D, 0X94, 0X4D, 0X94, 0X2C, + 0X94, 0X8F, 0X9C, 0XF2, 0X9C, 0XD1, 0X9D, 0X12, 0X7B, 0XCB, 0X73, 0X48, + 0X73, 0X69, 0X73, 0X49, 0X83, 0XCA, 0X8C, 0X0A, 0X8C, 0X2A, 0X63, 0X29, + 0X3A, 0X07, 0X52, 0XCA, 0X73, 0XCD, 0X9D, 0X12, 0XC6, 0X37, 0XD6, 0XD9, + 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, + 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, 0XDE, 0XFA, + 0XEF, 0X5C, 0XEF, 0X5C, 0XF7, 0X7C, 0XB5, 0XB5, 0X94, 0X91, 0X8C, 0X71, + 0X94, 0XB2, 0XD6, 0X57, 0X9C, 0XD2, 0XAD, 0X54, 0XE7, 0X1A, 0XDE, 0XDA, + 0XD6, 0XB9, 0XDE, 0XB9, 0XE6, 0XFB, 0XD6, 0XB9, 0X9D, 0X32, 0X9D, 0X32, + 0X9D, 0X32, 0X9D, 0X32, 0XBD, 0XB5, 0XBD, 0XB5, 0XBD, 0XB5, 0XAD, 0X53, + 0X52, 0X89, 0X4A, 0X68, 0X4A, 0X88, 0X4A, 0X68, 0X4A, 0X88, 0X4A, 0X88, + 0X4A, 0X88, 0X4A, 0X88, 0X4A, 0X88, 0X4A, 0X68, 0X4A, 0X88, 0X4A, 0X88, + 0X4A, 0X88, 0X4A, 0X88, 0X4A, 0X68, 0X4A, 0X88, 0X4A, 0X88, 0X4A, 0X68, + 0X4A, 0X88, 0X4A, 0X47, 0X4A, 0X05, 0X4A, 0X05, 0X4A, 0X05, 0X4A, 0X26, + 0X8C, 0X6F, 0X9C, 0XB0, 0X52, 0XA8, 0X42, 0X69, 0X4A, 0X48, 0X42, 0X27, + 0X42, 0X06, 0X41, 0XE5, 0X39, 0X85, 0X39, 0XA5, 0X39, 0XA4, 0X41, 0XC5, + 0X41, 0XC5, 0X52, 0X26, 0X5A, 0X86, 0X61, 0XE3, 0X61, 0XE3, 0X61, 0XE3, + 0X52, 0X25, 0X49, 0XE5, 0X49, 0XE5, 0X49, 0XE5, 0X52, 0X05, 0X4A, 0X05, + 0X41, 0XE6, 0X52, 0X26, 0X52, 0X26, 0X41, 0XE5, 0X31, 0XA4, 0X39, 0XC5, + 0X39, 0XC5, 0X31, 0XA4, 0X31, 0XA4, 0X39, 0XE5, 0X39, 0XE6, 0X4A, 0X47, + 0X4A, 0X47, 0X41, 0XE6, 0X39, 0XC5, 0X49, 0XE6, 0X41, 0XE6, 0X6B, 0X4B, + 0X52, 0XA9, 0X29, 0X84, 0X39, 0XC5, 0X41, 0X83, 0X5A, 0X67, 0X52, 0X47, + 0X39, 0XE6, 0X41, 0XE6, 0X41, 0XC5, 0X62, 0XA8, 0X52, 0X46, 0X49, 0XE5, + 0X4A, 0X06, 0X4A, 0X06, 0X4A, 0X06, 0X52, 0X26, 0X49, 0XE5, 0X39, 0X83, + 0X39, 0XA4, 0X29, 0X84, 0X39, 0XC5, 0X42, 0X05, 0X42, 0X05, 0X39, 0XE5, + 0X39, 0XC5, 0X52, 0X26, 0X49, 0XE6, 0X31, 0XA5, 0X4A, 0X89, 0X52, 0XCA, + 0X39, 0XA4, 0X4A, 0X05, 0X62, 0X26, 0X51, 0XE6, 0X29, 0X23, 0X00, 0X62, + 0X08, 0X62, 0X18, 0XC3, 0X10, 0XA2, 0X08, 0X82, 0X08, 0XA3, 0X10, 0XC3, + 0X08, 0XA3, 0X21, 0X03, 0X31, 0X65, 0X18, 0XE4, 0X18, 0XC3, 0X21, 0X24, + 0X29, 0X44, 0X21, 0X04, 0X29, 0X24, 0X19, 0X22, 0X10, 0XC2, 0X21, 0X23, + 0X18, 0XC2, 0X08, 0X62, 0X10, 0XC4, 0X10, 0XA3, 0X08, 0X82, 0X21, 0X25, + 0X31, 0X45, 0X20, 0XE3, 0X41, 0XE6, 0X4A, 0X48, 0X18, 0XE3, 0X21, 0X23, + 0X30, 0XE4, 0X20, 0XC4, 0X31, 0X86, 0X18, 0XC4, 0X20, 0XE3, 0X31, 0X43, + 0X10, 0X82, 0X18, 0XC2, 0X18, 0XC2, 0X18, 0XC2, 0X21, 0X05, 0X18, 0XE4, + 0X19, 0X05, 0X10, 0XA3, 0X18, 0XC3, 0X10, 0X62, 0X18, 0XE3, 0X31, 0X25, + 0X18, 0XE4, 0X18, 0XA2, 0X18, 0XA3, 0X31, 0X25, 0X31, 0X24, 0X29, 0X45, + 0X31, 0X44, 0X39, 0X87, 0X39, 0X87, 0X29, 0X24, 0X29, 0X23, 0X21, 0X43, + 0X10, 0XA2, 0X10, 0X82, 0X20, 0XE3, 0X10, 0XA2, 0X08, 0X61, 0X10, 0X82, + 0X10, 0X82, 0X08, 0X62, 0X31, 0X64, 0X52, 0X26, 0X39, 0XC5, 0X31, 0XC5, + 0X39, 0XA4, 0X41, 0XA4, 0X31, 0X84, 0X29, 0X84, 0X4A, 0X67, 0X5A, 0X67, + 0X63, 0X6D, 0X74, 0X72, 0X7C, 0X50, 0X84, 0X4E, 0X95, 0X32, 0XAD, 0XB5, + 0X8C, 0XF2, 0X9D, 0X53, 0X84, 0XB1, 0X9D, 0X53, 0X6B, 0XEF, 0X42, 0X28, + 0XBD, 0XD5, 0XB5, 0X94, 0XBD, 0XD5, 0XBD, 0XD5, 0XBD, 0XD5, 0XBD, 0XD5, + 0XBD, 0X94, 0XB5, 0X93, 0XA4, 0XF1, 0X6A, 0XE8, 0X7B, 0X8A, 0X83, 0XEC, + 0X7B, 0XCC, 0X7B, 0XAC, 0X7B, 0XAB, 0X7B, 0XAB, 0X7B, 0XCC, 0X6B, 0X29, + 0X5A, 0XA8, 0X8B, 0XCA, 0X8B, 0XCA, 0X7B, 0XAB, 0X7B, 0XCB, 0X7B, 0XAB, + 0X7B, 0XAB, 0X7B, 0XAB, 0X7B, 0XAB, 0X7B, 0XCB, 0X7B, 0XAB, 0X9C, 0XB0, + 0X9C, 0XD1, 0X6B, 0X09, 0X6A, 0XC7, 0X94, 0X2E, 0X9C, 0XB0, 0X9C, 0X90, + 0X9C, 0X90, 0X9C, 0X90, 0X9C, 0X6F, 0X9C, 0X6F, 0X94, 0X90, 0X83, 0XEC, + 0X7B, 0XCC, 0X7B, 0XCC, 0X7B, 0XCC, 0X7B, 0XCC, 0X83, 0XEC, 0X84, 0X0C, + 0X9C, 0XD1, 0X9C, 0XD2, 0X9C, 0XD2, 0XA5, 0X12, 0X6B, 0X2A, 0X29, 0X02, + 0X63, 0X2B, 0X5A, 0XCA, 0X52, 0X89, 0X4A, 0X67, 0X4A, 0X26, 0X52, 0X46, + 0X39, 0XC3, 0X39, 0XE4, 0X63, 0X6C, 0X9D, 0XB8, 0X73, 0XEF, 0X5A, 0XC8, + 0X5A, 0XE9, 0X7B, 0XEE, 0XAD, 0XB6, 0X84, 0X2F, 0X39, 0XA5, 0X73, 0X6B, + 0X84, 0XD3, 0X84, 0X70, 0X31, 0X85, 0X29, 0X44, 0X39, 0XE7, 0X95, 0X55, + 0X8D, 0X14, 0X6B, 0X8C, 0X6B, 0X8C, 0X6B, 0XAC, 0X52, 0X88, 0X5A, 0XE9, + 0X5B, 0X2A, 0X31, 0XA4, 0X31, 0XC4, 0X31, 0XC4, 0X31, 0XA4, 0X7B, 0XCD, + 0X8C, 0X6F, 0X84, 0X0E, 0X5A, 0XC9, 0X31, 0X63, 0X29, 0X22, 0X29, 0X22, + 0X21, 0X02, 0X31, 0X83, 0X4A, 0X24, 0X42, 0X04, 0X41, 0XE3, 0X52, 0X65, + 0X7B, 0XED, 0X73, 0X6A, 0X73, 0X49, 0X73, 0X4A, 0X73, 0X4A, 0X7B, 0X6A, + 0X7B, 0X6A, 0X7B, 0X6A, 0X7B, 0X6A, 0X7B, 0X6A, 0X7B, 0X6A, 0X7B, 0X8A, + 0X7B, 0X8B, 0X7B, 0XAC, 0X7B, 0XAC, 0X6B, 0X09, 0X6B, 0X29, 0X6B, 0X29, + 0X62, 0XE8, 0X63, 0X0A, 0X6B, 0X29, 0X5A, 0XE8, 0X63, 0X08, 0X63, 0X08, + 0X63, 0X08, 0X6B, 0X08, 0X63, 0X28, 0X63, 0X28, 0X63, 0X08, 0X63, 0X28, + 0X62, 0XE8, 0X62, 0XA7, 0X62, 0X86, 0X95, 0X55, 0XAE, 0XBD, 0XAE, 0X5B, + 0XAE, 0X5A, 0XA6, 0X18, 0X95, 0X34, 0X9D, 0X96, 0X95, 0X54, 0X95, 0X13, + 0X95, 0X34, 0X8C, 0XD2, 0X5A, 0XEA, 0X8C, 0XF3, 0X94, 0XF3, 0X9D, 0X54, + 0X73, 0X8D, 0X73, 0X8D, 0X9D, 0X75, 0X9D, 0X55, 0X95, 0X34, 0XA5, 0X95, + 0XC6, 0X79, 0XCE, 0X9A, 0X9D, 0X33, 0X84, 0X91, 0X8C, 0XB1, 0X73, 0XCB, + 0X63, 0X49, 0X6B, 0X29, 0X73, 0X48, 0X95, 0X54, 0X9D, 0XB7, 0X95, 0X55, + 0X8D, 0X35, 0X95, 0XD8, 0X9E, 0X19, 0XA6, 0X5A, 0X8C, 0XF3, 0X6B, 0XAD, + 0X8C, 0XB1, 0X9C, 0XF2, 0X94, 0XF2, 0X9D, 0X14, 0X9D, 0X34, 0X9D, 0X14, + 0X9D, 0X55, 0X94, 0X71, 0X84, 0X4F, 0X7B, 0X8B, 0X94, 0XB0, 0X94, 0XF2, + 0X8C, 0X2E, 0X7C, 0X70, 0X8C, 0XD2, 0X84, 0X0E, 0X8B, 0XAB, 0X83, 0X6A, + 0X7B, 0X6B, 0X8B, 0X29, 0X94, 0XF2, 0X7C, 0XB2, 0X83, 0XCE, 0X95, 0X34, + 0X6B, 0XAB, 0X52, 0X66, 0X52, 0X66, 0X4A, 0X66, 0X41, 0XC4, 0X39, 0X43, + 0X4A, 0X25, 0X5A, 0XE7, 0X5A, 0XA6, 0X84, 0X6F, 0X8C, 0X0D, 0X7B, 0X4A, + 0X63, 0X0A, 0X6B, 0X4A, 0X63, 0X49, 0X73, 0X87, 0X73, 0X67, 0X73, 0X67, + 0X52, 0X86, 0X73, 0X68, 0X7B, 0XC8, 0X7B, 0XA8, 0X52, 0X66, 0X31, 0X84, + 0X21, 0X64, 0X21, 0X44, 0X5A, 0XC8, 0X9C, 0X2B, 0X7B, 0XCB, 0X7B, 0XEC, + 0X7B, 0XEC, 0X7B, 0XEC, 0X95, 0X32, 0X9D, 0X32, 0X9C, 0XD0, 0X9C, 0XF0, + 0X9D, 0X32, 0XAE, 0X7A, 0XA5, 0XD6, 0X9D, 0X73, 0XA5, 0XB5, 0X9D, 0XB5, + 0X9D, 0X53, 0X9D, 0X73, 0XAE, 0X39, 0X9D, 0XB6, 0X8C, 0XF2, 0X8D, 0X12, + 0X8D, 0X12, 0X8C, 0XF2, 0X8D, 0X33, 0XA6, 0X59, 0X95, 0X95, 0X8D, 0X12, + 0X8D, 0X13, 0X8D, 0X13, 0XAE, 0X38, 0XB6, 0X79, 0XB6, 0X79, 0XB6, 0X58, + 0XB6, 0X58, 0XAE, 0X38, 0XA6, 0X39, 0XA6, 0X39, 0XA6, 0X39, 0X95, 0X74, + 0X8D, 0X12, 0X8D, 0X12, 0X8D, 0X12, 0X8D, 0X12, 0X8D, 0X12, 0X8D, 0X12, + 0X8C, 0XF2, 0X8C, 0XF2, 0X8D, 0X12, 0X84, 0XD1, 0X63, 0X4B, 0X63, 0X2A, + 0X8C, 0X90, 0X9D, 0X74, 0X7C, 0X0E, 0X4A, 0X25, 0X52, 0X26, 0X52, 0X46, + 0X4A, 0X06, 0X41, 0XE6, 0X42, 0X06, 0X42, 0X06, 0X42, 0X06, 0X39, 0XE6, + 0X42, 0X27, 0X4A, 0X69, 0X4A, 0X68, 0X4A, 0X68, 0X39, 0XA4, 0X41, 0XC4, + 0X4A, 0X05, 0X49, 0XE4, 0X39, 0XA4, 0X31, 0X83, 0X39, 0X83, 0X39, 0X83, + 0X31, 0X83, 0X39, 0X83, 0X31, 0X83, 0X39, 0X83, 0X41, 0XE5, 0X41, 0XE5, + 0X52, 0X26, 0X52, 0X26, 0X52, 0X46, 0X52, 0X05, 0X51, 0XE5, 0X4A, 0X05, + 0X52, 0X04, 0X4A, 0X05, 0X41, 0XE5, 0X39, 0XE5, 0X42, 0X26, 0X4A, 0X25, + 0X49, 0XA4, 0X41, 0XA5, 0X49, 0XC4, 0X52, 0X46, 0X5A, 0X45, 0X52, 0X25, + 0X4A, 0X26, 0X6B, 0X2A, 0XAD, 0X74, 0X94, 0X6F, 0X51, 0XE4, 0X52, 0X05, + 0X52, 0X45, 0X52, 0XC7, 0X52, 0XC7, 0X52, 0XC7, 0X5A, 0XC7, 0X62, 0X25, + 0X4A, 0X05, 0X59, 0XE3, 0X92, 0XC2, 0X5A, 0X05, 0X49, 0XE4, 0X8A, 0XC4, + 0XB3, 0X63, 0X9B, 0X23, 0XBB, 0X83, 0XE3, 0XA1, 0XD3, 0X42, 0XB3, 0X03, + 0XBB, 0X23, 0XBB, 0X43, 0XC3, 0X63, 0XC3, 0X62, 0XD4, 0X02, 0XD3, 0XE2, + 0XC3, 0X83, 0XC3, 0X64, 0XC3, 0X43, 0XB2, 0X82, 0X99, 0XE1, 0XD3, 0XC1, + 0XC3, 0X01, 0X89, 0X61, 0X69, 0X00, 0X81, 0X20, 0X81, 0X60, 0X71, 0XC1, + 0X89, 0XC1, 0X69, 0X20, 0X61, 0X20, 0X58, 0XC1, 0X60, 0XE1, 0X61, 0X00, + 0X50, 0XA0, 0X92, 0X02, 0XC3, 0X03, 0XBA, 0XE3, 0XD3, 0X82, 0XCB, 0X43, + 0XC3, 0X24, 0XBB, 0X86, 0XBB, 0X65, 0XBB, 0X65, 0XBB, 0X65, 0XBB, 0X65, + 0XA2, 0XC4, 0X8A, 0X22, 0XA2, 0X83, 0XC2, 0XE3, 0XE4, 0X87, 0XDC, 0XE8, + 0XC4, 0X46, 0XCC, 0X66, 0X7B, 0X07, 0X41, 0XE7, 0X52, 0XA9, 0X74, 0X4F, + 0X74, 0X2F, 0X73, 0XEE, 0X7B, 0XAC, 0XBD, 0XB6, 0XA5, 0X12, 0X41, 0XE5, + 0X10, 0X81, 0X18, 0XA2, 0X10, 0X61, 0X29, 0X43, 0X7C, 0X2C, 0X7C, 0X0C, + 0X7C, 0X0C, 0X7C, 0X0C, 0X7C, 0X0C, 0X7C, 0X0C, 0X7B, 0XA9, 0X7B, 0XEB, + 0X7B, 0XEB, 0X73, 0XCB, 0X7B, 0XEB, 0X93, 0X89, 0X8C, 0X0D, 0X8C, 0X90, + 0X8C, 0X8F, 0X8C, 0X6F, 0X84, 0X4F, 0X84, 0X6F, 0X8C, 0X6F, 0X8C, 0X90, + 0X94, 0X2C, 0X9C, 0X2C, 0X8C, 0X90, 0X84, 0X4F, 0X6B, 0X8C, 0X73, 0XCD, + 0X4A, 0X47, 0X18, 0XC2, 0X52, 0X88, 0X31, 0X85, 0X84, 0X70, 0X8C, 0X71, + 0X73, 0XCE, 0X20, 0XE2, 0X18, 0XA1, 0X29, 0X64, 0X7C, 0X50, 0X7C, 0X30, + 0X7C, 0X50, 0X7C, 0X4F, 0X7C, 0X4E, 0X74, 0X0D, 0X74, 0X0D, 0X7C, 0X2E, + 0X7C, 0X4E, 0X7C, 0X4E, 0X39, 0XC7, 0X5A, 0X68, 0X31, 0X44, 0X38, 0XC5, + 0X38, 0XA5, 0X49, 0X66, 0X5A, 0X27, 0X51, 0XA6, 0X61, 0XE6, 0X72, 0XEA, + 0X59, 0XE7, 0X83, 0X2B, 0X7A, 0XCA, 0X61, 0XE6, 0X5A, 0X06, 0X5A, 0X47, + 0X6A, 0XCA, 0X61, 0XE7, 0X72, 0XCA, 0X6A, 0XCA, 0X72, 0XA9, 0X72, 0X88, + 0X72, 0X27, 0X72, 0X47, 0X6A, 0XEA, 0X72, 0X68, 0X73, 0X0B, 0X5A, 0XA8, + 0X52, 0X26, 0X6A, 0X47, 0X4A, 0X26, 0X6A, 0X27, 0X52, 0X06, 0X59, 0XA5, + 0X6A, 0X06, 0X62, 0X26, 0X62, 0X26, 0X62, 0X05, 0X62, 0X06, 0X59, 0XC5, + 0X62, 0X06, 0X7A, 0X67, 0X93, 0X0A, 0X82, 0X87, 0X72, 0X26, 0X72, 0X06, + 0X69, 0XC5, 0X69, 0XC5, 0X71, 0XE6, 0X6A, 0X06, 0X82, 0X06, 0X71, 0XE6, + 0X8A, 0XA8, 0X7A, 0X67, 0X7A, 0X06, 0X82, 0X47, 0X8A, 0XE9, 0X6A, 0X27, + 0X6A, 0X47, 0X71, 0XE5, 0X7A, 0X67, 0X82, 0XE9, 0X8A, 0XE9, 0X7A, 0X26, + 0X82, 0XA8, 0X8A, 0X47, 0X72, 0X06, 0X62, 0X06, 0X83, 0X09, 0X82, 0X87, + 0X72, 0X47, 0X82, 0X26, 0X71, 0X85, 0X69, 0XE6, 0X71, 0XE6, 0X69, 0XA5, + 0X61, 0XA5, 0X51, 0X85, 0X52, 0X06, 0X52, 0X26, 0X4A, 0X26, 0X62, 0X07, + 0X7A, 0X07, 0X69, 0XA6, 0X51, 0X03, 0X59, 0X23, 0X50, 0XE2, 0X48, 0XA1, + 0X48, 0XE3, 0X40, 0XE3, 0X30, 0XE4, 0X29, 0X04, 0X38, 0XE3, 0X50, 0XE3, + 0X51, 0X03, 0X48, 0XE2, 0X40, 0XC2, 0X49, 0X23, 0X51, 0X64, 0X51, 0X64, + 0X51, 0X44, 0X51, 0X44, 0X49, 0X43, 0X49, 0X44, 0X30, 0XC2, 0X30, 0XC2, + 0X30, 0XC2, 0X38, 0XC3, 0X30, 0XC2, 0X28, 0XC2, 0X38, 0XE3, 0X50, 0XE3, + 0X38, 0XC3, 0X30, 0XA2, 0X28, 0XA2, 0X28, 0XA2, 0X38, 0XA2, 0X40, 0XC2, + 0X38, 0XC3, 0X38, 0XC3, 0X38, 0XA2, 0X38, 0XC2, 0X30, 0XA2, 0X30, 0XA2, + 0X40, 0XE2, 0X41, 0X03, 0X41, 0X43, 0X10, 0X41, 0X41, 0XA5, 0X83, 0X49, + 0X6A, 0XE9, 0X7B, 0X8B, 0X8A, 0X87, 0XBB, 0X68, 0X7A, 0XE9, 0X6B, 0X2A, + 0X6A, 0XE9, 0X83, 0X6A, 0X5A, 0X47, 0X62, 0X87, 0X7B, 0X29, 0X8B, 0X89, + 0XBD, 0X96, 0X8C, 0X51, 0X49, 0XE8, 0X41, 0XC7, 0X21, 0X24, 0X21, 0X44, + 0X29, 0X44, 0X31, 0X44, 0X41, 0X24, 0X20, 0XE2, 0X18, 0XE3, 0X29, 0X24, + 0X48, 0XC3, 0X50, 0XE2, 0X40, 0XC2, 0X40, 0XA2, 0X48, 0XA2, 0X40, 0X81, + 0X48, 0XC2, 0X40, 0XC2, 0X48, 0XE3, 0X30, 0X81, 0X28, 0X61, 0X38, 0XE3, + 0X30, 0XC3, 0X51, 0X23, 0X41, 0X63, 0X32, 0X06, 0X31, 0X84, 0X21, 0X45, + 0X2A, 0X88, 0X2A, 0X07, 0X3B, 0X29, 0X33, 0XAD, 0X3B, 0X6D, 0X2A, 0X68, + 0X22, 0X27, 0X2A, 0X88, 0X3B, 0X0B, 0X2A, 0XC9, 0X32, 0X27, 0X32, 0XAA, + 0X3A, 0XAA, 0X32, 0X69, 0X22, 0X08, 0X32, 0XA9, 0X4C, 0X6C, 0X52, 0XA8, + 0X39, 0X24, 0X21, 0XC6, 0X31, 0X44, 0X28, 0XC2, 0X19, 0X44, 0X22, 0X27, + 0X22, 0X47, 0X2A, 0X47, 0X2A, 0XC9, 0X2A, 0X89, 0X19, 0X65, 0X19, 0XE7, + 0X21, 0X85, 0X21, 0X44, 0X21, 0X85, 0X21, 0X44, 0X21, 0X64, 0X21, 0X64, + 0X31, 0XC6, 0X31, 0XE6, 0X2A, 0X07, 0X21, 0X65, 0X21, 0X65, 0X21, 0X85, + 0X19, 0X24, 0X11, 0X24, 0X2A, 0X47, 0X39, 0X86, 0X5A, 0X28, 0X39, 0X46, + 0X51, 0X87, 0X62, 0X29, 0X39, 0X65, 0X29, 0X03, 0X52, 0X47, 0X4A, 0X26, + 0X31, 0X65, 0X49, 0XE7, 0XAB, 0X6C, 0X6A, 0X27, 0X39, 0XC6, 0X4A, 0X47, + 0X4A, 0X69, 0X52, 0X08, 0X49, 0XC6, 0X52, 0X06, 0X7A, 0X89, 0XA3, 0X4C, + 0X41, 0X86, 0X4A, 0X06, 0X31, 0X44, 0X10, 0XA2, 0X10, 0X82, 0X20, 0XA3, + 0X41, 0XA5, 0X52, 0X47, 0X49, 0XC6, 0X31, 0X24, 0X20, 0XC3, 0X28, 0XE3, + 0X20, 0XA3, 0X52, 0X07, 0X89, 0XA5, 0X59, 0X63, 0X59, 0XC5, 0X61, 0X23, + 0X69, 0X23, 0X58, 0XE3, 0X50, 0XE2, 0X69, 0X63, 0X69, 0X63, 0X61, 0X43, + 0X31, 0X23, 0X39, 0X44, 0X51, 0XC6, 0X51, 0X84, 0X51, 0X64, 0X61, 0XC6, + 0X51, 0XC6, 0X59, 0XA5, 0X62, 0X26, 0X59, 0XC6, 0X4A, 0X06, 0X11, 0X65, + 0X11, 0X24, 0X11, 0X24, 0X21, 0XE7, 0X19, 0X86, 0X22, 0X07, 0X22, 0X07, + 0X21, 0XC6, 0X21, 0XC6, 0X29, 0XC6, 0X31, 0X45, 0X49, 0X85, 0X62, 0X27, + 0X31, 0X65, 0X19, 0X85, 0X19, 0X03, 0X19, 0X03, 0X21, 0X65, 0X29, 0XE6, + 0X21, 0X44, 0X21, 0XE6, 0X19, 0X65, 0X11, 0X03, 0X11, 0X24, 0X19, 0X85, + 0X21, 0XC6, 0X19, 0XC6, 0X11, 0X03, 0X10, 0XE3, 0X21, 0XC7, 0X19, 0X85, + 0X19, 0XA6, 0X19, 0XA6, 0X21, 0XC6, 0X22, 0X28, 0X19, 0X65, 0X19, 0X65, + 0X2A, 0X89, 0X4B, 0X8C, 0X6A, 0XE9, 0X7A, 0X68, 0X39, 0X25, 0X3A, 0X68, + 0X3A, 0X68, 0X21, 0X85, 0X19, 0XC6, 0X19, 0X85, 0X1A, 0X07, 0X22, 0X48, + 0X2A, 0X27, 0X3A, 0X69, 0X29, 0XC6, 0X11, 0X23, 0X21, 0XC6, 0X22, 0X28, + 0X19, 0X44, 0X08, 0XA2, 0X19, 0X24, 0X31, 0XA5, 0X31, 0XC5, 0X19, 0XC6, + 0X21, 0X85, 0X21, 0XC6, 0X31, 0X03, 0X52, 0X06, 0X73, 0X09, 0X72, 0XC8, + 0X41, 0X64, 0X39, 0XA6, 0XA5, 0X32, 0XAC, 0XF2, 0X94, 0X0E, 0XBD, 0X12, + 0XBC, 0XD1, 0XBC, 0X91, 0XBB, 0XB1, 0XAB, 0XCF, 0X7A, 0XA9, 0XA3, 0X8D, + 0XCB, 0XF4, 0XCA, 0XF7, 0XCB, 0X32, 0XC3, 0X0C, 0XCB, 0XCF, 0XCC, 0X91, + 0XC4, 0X30, 0XB4, 0X2F, 0X9C, 0X0E, 0XAA, 0XCB, 0XCB, 0XCF, 0XC3, 0XEF, + 0XC4, 0X0F, 0XCC, 0XD2, 0XD6, 0X97, 0XDC, 0XB3, 0XD3, 0X8F, 0XCC, 0X0F, + 0XB5, 0XF4, 0XD3, 0XEF, 0XC3, 0XEE, 0XC3, 0XAE, 0XC4, 0X0F, 0XC4, 0XF0, + 0XBC, 0X8F, 0XAB, 0X4C, 0XAA, 0XCB, 0XBC, 0X2F, 0XC5, 0X12, 0XAB, 0X0C, + 0XBC, 0X70, 0XBB, 0XAE, 0XD4, 0XF3, 0XD4, 0XD3, 0XCC, 0XD2, 0XC3, 0XF0, + 0XD3, 0X8F, 0XAB, 0X0C, 0X91, 0XE8, 0XAB, 0XAD, 0XB4, 0X2F, 0XA3, 0X2C, + 0XAB, 0X8D, 0X9A, 0X29, 0X92, 0X49, 0XB3, 0X2D, 0XDB, 0X0D, 0XCC, 0XD1, + 0XC5, 0X54, 0XC4, 0X91, 0XC2, 0XEC, 0XB5, 0X32, 0XAE, 0X15, 0XCC, 0X50, + 0XCD, 0X13, 0XBE, 0XB7, 0XAF, 0X79, 0XC6, 0X16, 0XC5, 0XD4, 0XD5, 0X95, + 0XD3, 0XCF, 0XD3, 0XAF, 0XDB, 0X0E, 0XCB, 0X0E, 0XA3, 0X2D, 0XCB, 0X2E, + 0XD3, 0X4F, 0XD3, 0X0E, 0XDB, 0X2F, 0XD3, 0X6F, 0XDB, 0XCF, 0XCB, 0X8E, + 0X7B, 0X09, 0X72, 0XE8, 0X62, 0XA8, 0X5A, 0X67, 0X5A, 0X67, 0X52, 0X06, + 0X52, 0X05, 0X5A, 0X66, 0X5A, 0X66, 0X41, 0XC5, 0X49, 0XC5, 0X41, 0XA5, + 0X62, 0XA8, 0X62, 0XA8, 0X52, 0X06, 0X7B, 0X29, 0X7B, 0X6A, 0X6A, 0XE8, + 0X52, 0X05, 0X6A, 0XC8, 0X6A, 0XC8, 0X5A, 0X67, 0X39, 0X43, 0X61, 0XE3, + 0X93, 0X07, 0X93, 0X26, 0X93, 0X67, 0X9B, 0XCA, 0X31, 0XA5, 0X31, 0XE6, + 0X31, 0XA5, 0X31, 0XA5, 0X31, 0X85, 0X31, 0X85, 0X31, 0XC5, 0X31, 0XE5, + 0X31, 0XE6, 0X29, 0XC6, 0X21, 0XC5, 0X62, 0X46, 0XCC, 0X8F, 0XBC, 0X70, + 0XB4, 0XB0, 0XBC, 0X4E, 0XC4, 0X2D, 0XB3, 0XEE, 0XAB, 0X6B, 0XCC, 0XAB, + 0XCC, 0X6C, 0XBB, 0XCE, 0XCC, 0X91, 0XB4, 0X50, 0XAB, 0XEE, 0XA3, 0XCE, + 0XAB, 0XEC, 0XAB, 0XCC, 0X9B, 0XCE, 0XB4, 0X0E, 0XBC, 0X4C, 0XA3, 0XCE, + 0XB4, 0X2F, 0X62, 0X08, 0X73, 0X4D, 0XAC, 0X70, 0XBB, 0XAB, 0XAB, 0X8C, + 0XA3, 0XEF, 0XB4, 0X0D, 0XA4, 0X2A, 0XA3, 0XEE, 0XC4, 0X4D, 0XB5, 0X31, + 0XAC, 0X2E, 0XC4, 0X2E, 0X8B, 0X0A, 0X84, 0X2E, 0XC4, 0XD0, 0XC4, 0X0D, + 0X81, 0XE8, 0X71, 0X87, 0XB3, 0X8B, 0XBC, 0X6F, 0XB4, 0X2E, 0XBC, 0X4D, + 0XBC, 0X6E, 0XC4, 0X0D, 0XBC, 0X4D, 0XA3, 0XAC, 0X52, 0XAA, 0XAD, 0X12, + 0XA4, 0X0E, 0XBB, 0XCA, 0XAC, 0X0D, 0X9C, 0X70, 0X9B, 0XAC, 0XAC, 0X50, + 0XBC, 0X0E, 0X92, 0X46, 0XB3, 0X69, 0X93, 0X8C, 0XB4, 0X4E, 0XA4, 0X2C, + 0XAC, 0X0C, 0X71, 0XA5, 0X93, 0X4B, 0XC4, 0X2E, 0X72, 0X69, 0X93, 0X4B, + 0XA5, 0X10, 0X9C, 0X91, 0XAC, 0X6F, 0XB3, 0XCD, 0XAB, 0XED, 0XAC, 0X8F, + 0XAB, 0X6C, 0XAB, 0X6B, 0XA3, 0X6B, 0XA3, 0X8C, 0XC4, 0XCD, 0X92, 0XE8, + 0X9B, 0X2A, 0XB3, 0XEC, 0XA3, 0X8C, 0XA3, 0X4C, 0XA3, 0X8C, 0X9C, 0X0C, + 0XA5, 0X51, 0X73, 0X6B, 0X62, 0X88, 0X71, 0XE8, 0X7A, 0X08, 0X92, 0X08, + 0XB2, 0X8A, 0XB2, 0X6A, 0X82, 0X08, 0X82, 0X68, 0XAA, 0XAA, 0X92, 0X69, + 0XAA, 0XCA, 0X8A, 0X29, 0X8A, 0X48, 0X82, 0X28, 0X82, 0X28, 0X82, 0X48, + 0X92, 0X48, 0X82, 0X48, 0XA2, 0XAA, 0XA2, 0XA9, 0X92, 0X48, 0XA2, 0X48, + 0X92, 0X69, 0X8A, 0X89, 0XAA, 0XEA, 0XB3, 0X0A, 0X9A, 0X89, 0X92, 0X89, + 0XAA, 0XEA, 0X92, 0XA9, 0XAA, 0XEB, 0X9A, 0XCA, 0X9A, 0XA9, 0X9A, 0XA9, + 0XA2, 0XCA, 0X9A, 0XCA, 0X92, 0X69, 0XAA, 0XCA, 0XAA, 0XC9, 0XA2, 0XA9, + 0X9A, 0XA9, 0XA2, 0XCA, 0XAA, 0XEA, 0X9A, 0X69, 0X9A, 0X08, 0X81, 0XE8, + 0X82, 0X28, 0X82, 0X48, 0X82, 0X28, 0X92, 0X29, 0XAB, 0XAB, 0X92, 0XC8, + 0X7A, 0X07, 0X72, 0X8A, 0X9A, 0X69, 0XAA, 0X89, 0X9A, 0X48, 0X9A, 0XAA, + 0X82, 0X47, 0X7A, 0X06, 0X82, 0X26, 0X82, 0X06, 0X82, 0X48, 0X8A, 0X07, + 0XAB, 0X6C, 0XA3, 0X6C, 0X93, 0X0B, 0X9B, 0X8C, 0X9A, 0XC9, 0X92, 0X88, + 0X93, 0X4B, 0X92, 0XC9, 0X92, 0X68, 0X92, 0X68, 0XA2, 0XC9, 0XAB, 0X0A, + 0XAB, 0X0A, 0X92, 0X88, 0X8A, 0X68, 0X9A, 0XA9, 0X9A, 0XA9, 0X92, 0X88, + 0X92, 0XEA, 0X82, 0X69, 0X82, 0X68, 0X82, 0X68, 0X82, 0X68, 0X8A, 0XA9, + 0X8A, 0X89, 0X9B, 0XAD, 0X92, 0XE9, 0X72, 0X27, 0X7A, 0X48, 0X92, 0XA9, + 0X92, 0XEA, 0X9B, 0XAD, 0X92, 0XE9, 0X9A, 0XA9, 0X9A, 0XEA, 0XAC, 0X4F, + 0XAC, 0X90, 0XA4, 0X0E, 0XAA, 0X67, 0XA3, 0X8C, 0XA3, 0X4A, 0XB2, 0XC7, + 0X9B, 0X8C, 0XA2, 0XE9, 0XB2, 0XE8, 0X93, 0XAD, 0XAB, 0X8B, 0XAA, 0XE9, + 0X9A, 0XC9, 0XBB, 0X69, 0XB3, 0X49, 0XB4, 0X4F, 0XB3, 0XAB, 0XB3, 0X49, + 0XB3, 0XCC, 0XB3, 0XAB, 0X92, 0X8A, 0X92, 0X6A, 0XA2, 0XA8, 0X9A, 0X89, + 0X92, 0XEC, 0XA2, 0X8A, 0X9A, 0XA9, 0X93, 0X4C, 0X92, 0XA9, 0X92, 0X68, + 0X92, 0X8A, 0X9A, 0XAA, 0X81, 0XE6, 0X79, 0XC6, 0X79, 0XC6, 0X79, 0XC6, + 0X71, 0X86, 0X81, 0XC5, 0X79, 0XA6, 0X79, 0XA6, 0X79, 0XA5, 0X79, 0XC6, + 0XA2, 0XC8, 0X82, 0X07, 0X9A, 0X88, 0X79, 0X86, 0X9A, 0XA9, 0XAA, 0XCB, + 0XAA, 0X2A, 0XCB, 0X6F, 0XB3, 0X4E, 0X7C, 0XB0, 0X6C, 0X0E, 0X39, 0XA5, + 0X74, 0XD0, 0XBC, 0X71, 0XCA, 0XCD, 0XA2, 0X6D, 0XB2, 0X8F, 0X92, 0X2B, + 0X92, 0X2B, 0XB2, 0X6F, 0XB2, 0X90, 0XC2, 0XD0, 0X41, 0X25, 0X20, 0XE3, + 0X52, 0X4C, 0X52, 0X4C, 0X30, 0XE3, 0X29, 0X06, 0X31, 0X48, 0X20, 0X83, + 0X31, 0XA6, 0X4A, 0XE9, 0X3A, 0X27, 0X41, 0XC7, 0X39, 0X87, 0X30, 0XE4, + 0X39, 0X03, 0X51, 0X65, 0X79, 0XA6, 0X9A, 0X49, 0XCB, 0X4C, 0XB2, 0XEB, + 0X59, 0X03, 0X51, 0X23, 0X49, 0X24, 0X41, 0X24, 0X49, 0X03, 0X50, 0XE3, + 0X51, 0X03, 0X61, 0X23, 0X59, 0X03, 0X61, 0XA6, 0XDC, 0XF0, 0X71, 0XA5, + 0X71, 0XA5, 0XAB, 0XAC, 0X59, 0X03, 0X61, 0X44, 0X61, 0X23, 0X9B, 0X0A, + 0X51, 0X44, 0X61, 0X44, 0X69, 0X84, 0X61, 0X23, 0X92, 0XE9, 0X93, 0X0A, + 0X69, 0X84, 0XAB, 0XEE, 0X50, 0XE3, 0X7A, 0X26, 0X8A, 0XC9, 0X8A, 0X68, + 0XCB, 0XEF, 0XCB, 0XEF, 0XC3, 0XCF, 0XCB, 0XF0, 0XDC, 0XB1, 0XDC, 0X90, + 0XBB, 0X4D, 0XBB, 0X4D, 0XB2, 0XEC, 0XBB, 0X0C, 0X39, 0X04, 0X08, 0X40, + 0X18, 0X82, 0X7B, 0XCB, 0X94, 0XAD, 0X8C, 0X6C, 0X9C, 0X6C, 0X63, 0X89, + 0X33, 0X87, 0X43, 0XC8, 0X3B, 0XA7, 0X3B, 0XA7, 0X10, 0XC2, 0X18, 0X41, + 0X28, 0XA3, 0X30, 0XC3, 0X30, 0XA3, 0X28, 0X83, 0X20, 0XC2, 0X5A, 0X27, + 0X51, 0XC6, 0X5A, 0X07, 0X6A, 0X47, 0X9B, 0XCC, 0X61, 0XC6, 0X9B, 0X0A, + 0XA3, 0X6B, 0X8B, 0X6B, 0X82, 0XC8, 0X6A, 0X25, 0X72, 0X67, 0X72, 0X46, + 0X72, 0X26, 0X62, 0X07, 0X62, 0X46, 0X8A, 0X07, 0X8A, 0X07, 0X82, 0X27, + 0X72, 0X67, 0X92, 0XCA, 0X62, 0X48, 0X51, 0XC6, 0X9B, 0X0B, 0X72, 0X28, + 0X8A, 0X69, 0X6A, 0X89, 0X41, 0XA6, 0X41, 0XE7, 0X59, 0XE7, 0X82, 0X28, + 0X59, 0XA6, 0X59, 0XA6, 0X69, 0XA7, 0X71, 0XC7, 0X7A, 0X08, 0X82, 0X09, + 0X69, 0XC7, 0X81, 0XC7, 0X69, 0X86, 0X41, 0X24, 0X51, 0X85, 0X8B, 0X2A, + 0X8B, 0XAB, 0X9B, 0XEC, 0X9B, 0X6A, 0X8A, 0X88, 0X60, 0XE4, 0X61, 0X44, + 0X59, 0X85, 0X61, 0X65, 0X62, 0X07, 0X72, 0XCB, 0X7A, 0XAA, 0X72, 0X49, + 0X69, 0X86, 0X69, 0X65, 0X61, 0XE7, 0X72, 0XCB, 0X7A, 0XCB, 0X94, 0X2E, + 0X8C, 0X2B, 0X83, 0X8B, 0X7A, 0X89, 0X71, 0XC7, 0X7A, 0X4B, 0XA3, 0X0E, + 0X7A, 0X2A, 0X7A, 0X6A, 0X9B, 0X4C, 0X71, 0XE7, 0X72, 0X49, 0X18, 0X41, + 0X61, 0XE6, 0XA3, 0X4B, 0X61, 0X26, 0X59, 0X65, 0X59, 0X65, 0X61, 0X86, + 0X51, 0X04, 0X28, 0X60, 0X30, 0XA2, 0X30, 0XA1, 0X28, 0X81, 0X30, 0XA2, + 0X30, 0XA1, 0X30, 0XA1, 0X28, 0XA1, 0X28, 0X61, 0X30, 0X61, 0X30, 0X81, + 0X38, 0X81, 0X30, 0X61, 0X30, 0X61, 0X30, 0X81, 0X30, 0XA1, 0X38, 0X61, + 0X28, 0XA1, 0X30, 0XA1, 0X38, 0XC1, 0X49, 0X02, 0X38, 0XA1, 0X30, 0X81, + 0X30, 0XC2, 0X20, 0XE4, 0X40, 0XE3, 0X61, 0X24, 0X59, 0X23, 0X29, 0X04, + 0X59, 0X23, 0X51, 0X03, 0X79, 0X63, 0X49, 0X02, 0X28, 0XC3, 0X20, 0XA3, + 0X59, 0X22, 0X59, 0X22, 0X40, 0XE2, 0X48, 0XE1, 0X49, 0X01, 0X40, 0XE3, + 0X40, 0XE3, 0X49, 0X01, 0X49, 0X01, 0X49, 0X02, 0X40, 0XC3, 0X40, 0XC3, + 0X49, 0X02, 0X49, 0X01, 0X49, 0X21, 0X48, 0XE2, 0X40, 0XC3, 0X51, 0X03, + 0X59, 0X22, 0X59, 0X63, 0X51, 0X23, 0X51, 0X23, 0X49, 0X24, 0X50, 0XE1, + 0X49, 0X02, 0X49, 0X03, 0X40, 0XE3, 0X49, 0X04, 0X51, 0X23, 0X50, 0XE4, + 0X51, 0X03, 0X51, 0X23, 0X59, 0X24, 0X71, 0X44, 0X69, 0X04, 0X69, 0X04, + 0X59, 0X23, 0X49, 0X03, 0X51, 0X44, 0X51, 0X64, 0X51, 0X44, 0X59, 0X65, + 0X51, 0X24, 0X59, 0X85, 0X51, 0X43, 0X59, 0X43, 0X49, 0X02, 0X30, 0XA2, + 0X51, 0X03, 0X49, 0X02, 0X48, 0XE2, 0X51, 0X03, 0X41, 0X03, 0X39, 0X02, + 0X38, 0XC2, 0X30, 0XA2, 0X30, 0XE2, 0X28, 0XA2, 0X30, 0XA2, 0X38, 0XE4, + 0X30, 0XC4, 0X28, 0XC3, 0X20, 0XC4, 0X7A, 0X26, 0X8A, 0X45, 0X28, 0X82, + 0X59, 0X23, 0X39, 0X03, 0X39, 0X04, 0X49, 0X04, 0X49, 0X23, 0X49, 0X24, + 0X49, 0X04, 0X49, 0X03, 0X41, 0X03, 0XBD, 0X91, 0XA4, 0XF0, 0X59, 0X06, + 0X49, 0X05, 0X59, 0X45, 0X81, 0XE8, 0X79, 0XA8, 0X61, 0X26, 0X69, 0X47, + 0X69, 0X67, 0X82, 0X09, 0X61, 0X06, 0X3A, 0XCD, 0X34, 0X32, 0X3B, 0X0C, + 0X20, 0X82, 0X31, 0X44, 0X31, 0X84, 0X10, 0X81, 0X10, 0X81, 0X28, 0XE3, + 0X20, 0XE3, 0X3A, 0X2A, 0X31, 0X25, 0X18, 0X82, 0X20, 0XA2, 0X20, 0XA3, + 0X20, 0X82, 0X31, 0XA7, 0X31, 0XE9, 0X18, 0X82, 0X18, 0XA3, 0X18, 0X82, + 0X18, 0X82, 0X20, 0XC3, 0X18, 0XA2, 0X20, 0XE3, 0X29, 0X04, 0X29, 0X24, + 0X29, 0X24, 0X29, 0X03, 0X20, 0XA2, 0X18, 0X61, 0X18, 0X82, 0X18, 0X61, + 0X21, 0X86, 0X21, 0XE9, 0X20, 0X81, 0X20, 0XC2, 0X18, 0XA2, 0X31, 0X23, + 0X39, 0X24, 0X31, 0X23, 0X28, 0XA2, 0X31, 0X03, 0X29, 0X03, 0X31, 0X04, + 0X41, 0X87, 0X31, 0X45, 0X29, 0X04, 0X39, 0XA6, 0X39, 0XA6, 0X39, 0XA6, + 0X39, 0X85, 0X39, 0X65, 0X39, 0XA6, 0X39, 0X86, 0X39, 0XA6, 0X39, 0XA6, + 0X39, 0XA6, 0X29, 0X03, 0X28, 0XE3, 0X31, 0X24, 0X41, 0X66, 0X39, 0XA6, + 0X31, 0X45, 0X31, 0X65, 0X39, 0X85, 0X31, 0XA6, 0X29, 0X04, 0X41, 0X85, + 0X62, 0X88, 0X21, 0X04, 0X39, 0X86, 0X49, 0XC6, 0X41, 0XA6, 0X41, 0XA6, + 0X39, 0X86, 0X41, 0XA6, 0X31, 0X85, 0X08, 0XE3, 0X18, 0XE4, 0X18, 0XE5, + 0X19, 0X05, 0X19, 0X05, 0X18, 0XE5, 0X10, 0XE4, 0X10, 0XE4, 0X18, 0XE4, + 0X21, 0X05, 0X21, 0X05, 0X21, 0X04, 0X18, 0XE4, 0X10, 0XE4, 0X10, 0XE3, + 0X39, 0X23, 0X28, 0XE3, 0X31, 0X03, 0X20, 0XC3, 0X49, 0X84, 0X61, 0XE5, + 0X61, 0XE5, 0X51, 0X84, 0X59, 0XC5, 0X39, 0X23, 0X39, 0X44, 0XFF, 0XBD, + 0X94, 0X52, 0X10, 0X41, 0X8A, 0XE9, 0X9B, 0X4A, 0X61, 0X84, 0XAB, 0XEE, + 0X9C, 0X91, 0X00, 0X00, 0X31, 0X23, 0X39, 0X43, 0X18, 0XE3, 0X08, 0XA2, + 0X42, 0XEC, 0X53, 0X6E, 0X32, 0X4A, 0X08, 0XA2, 0X19, 0X04, 0X21, 0X45, + 0X29, 0X66, 0X31, 0XA6, 0X29, 0X86, 0X29, 0XA6, 0X32, 0X08, 0X2A, 0X29, + 0X22, 0X08, 0X22, 0X29, 0X19, 0XC7, 0X08, 0X62, 0X63, 0X4F, 0X5B, 0X4E, + 0X29, 0XA6, 0X29, 0XA7, 0X31, 0XA6, 0X31, 0XA6, 0X29, 0X45, 0X29, 0X65, + 0X29, 0X65, 0X3A, 0X49, 0X31, 0XA6, 0X39, 0XE7, 0X3A, 0X08, 0X3A, 0X28, + 0X4A, 0X49, 0X42, 0X28, 0X39, 0XE7, 0X63, 0X2C, 0X4A, 0X49, 0X18, 0XC3, + 0X21, 0X25, 0X29, 0X45, 0X29, 0X45, 0X29, 0X45, 0X29, 0X66, 0X21, 0X24, + 0X29, 0X45, 0X31, 0XA5, 0X39, 0XC6, 0X31, 0X86, 0X29, 0X65, 0X42, 0X08, + 0X5A, 0X8A, 0X92, 0X07, 0X7B, 0XCB, 0X5A, 0X87, 0X49, 0XE5, 0X52, 0X26, + 0X52, 0X26, 0X6B, 0X2C, 0X62, 0XA9, 0X52, 0X26, 0X52, 0X26, 0X52, 0X26, + 0X62, 0XA9, 0X62, 0XA9, 0X6B, 0X4C, 0X73, 0XAF, 0X73, 0X2A, 0X73, 0X6D, + 0X73, 0X6C, 0X73, 0X4A, 0X6B, 0X4C, 0X5A, 0XCA, 0X5A, 0X89, 0X4A, 0X48, + 0X39, 0XE7, 0X52, 0X48, 0X52, 0X89, 0X62, 0XEA, 0X5A, 0XA9, 0X63, 0X0B, + 0X4A, 0X69, 0X5A, 0XAA, 0X73, 0X8D, 0X6B, 0X2B, 0X5B, 0X0B, 0X1A, 0X8B, + 0X1A, 0X8B, 0X3A, 0XAA, 0X6A, 0XEA, 0X62, 0XC9, 0X6B, 0X4B, 0X6B, 0X4B, + 0X62, 0XA8, 0X83, 0X4A, 0X52, 0X67, 0X52, 0X67, 0X21, 0X03, 0X10, 0X81, + 0X29, 0X24, 0X39, 0X85, 0X39, 0XA6, 0X62, 0XEB, 0X63, 0X0B, 0X63, 0X0B, + 0X52, 0X48, 0X52, 0X48, 0X62, 0XCA, 0X52, 0XCA, 0X1A, 0XCC, 0X4A, 0XEA, + 0X5A, 0X89, 0X5A, 0XA9, 0X62, 0XCA, 0X41, 0XE7, 0X39, 0XE7, 0X41, 0XE7, + 0X41, 0XE7, 0X41, 0XC6, 0X52, 0X6A, 0X6B, 0X2D, 0X7B, 0XF1, 0X39, 0XC6, + 0X52, 0X67, 0X52, 0X88, 0X52, 0X47, 0X62, 0XC9, 0X6B, 0X6D, 0X62, 0XEA, + 0X31, 0X44, 0X41, 0XA5, 0X6B, 0X2B, 0X6B, 0X4D, 0X6B, 0X0B, 0X6B, 0X4D, + 0X52, 0X8A, 0X73, 0X4D, 0X6B, 0X2C, 0X6B, 0X4E, 0X73, 0XD0, 0X5A, 0XCB, + 0X39, 0XE8, 0X4A, 0X6A, 0X6B, 0X2C, 0X52, 0X6A, 0X49, 0XE7, 0X4A, 0X07, + 0X49, 0XE6, 0X6B, 0X0B, 0X73, 0X6E, 0X4A, 0X49, 0X39, 0XE7, 0X42, 0X08, + 0X42, 0X08, 0X31, 0X86, 0X62, 0XEB, 0X52, 0X8A, 0X39, 0X86, 0X6B, 0X2D, + 0X62, 0XEC, 0X5A, 0X88, 0X62, 0XC9, 0X6B, 0X2A, 0X29, 0X44, 0X20, 0XE3, + 0X18, 0XA2, 0X18, 0XE3, 0X42, 0X06, 0X5A, 0XA8, 0X5A, 0X88, 0X4A, 0X27, + 0X39, 0X85, 0X52, 0X67, 0X62, 0XC8, 0X31, 0X85, 0X39, 0XA5, 0X21, 0X03, + 0X00, 0X41, 0X08, 0X62, 0X10, 0XA2, 0X10, 0XA3, 0X08, 0X82, 0X10, 0XA2, + 0X08, 0X82, 0X10, 0XE4, 0X19, 0X65, 0X2A, 0X48, 0X32, 0X8A, 0X11, 0X04, + 0X11, 0X04, 0X19, 0X24, 0X08, 0XA2, 0X18, 0XE3, 0X10, 0XC3, 0X10, 0XA3, + 0X11, 0X24, 0X19, 0X04, 0X21, 0XA7, 0X21, 0XC8, 0X19, 0X87, 0X19, 0X25, + 0X19, 0X24, 0X11, 0X04, 0X10, 0XC3, 0X19, 0X04, 0X19, 0X25, 0X10, 0XC3, + 0X18, 0XC3, 0X10, 0XC3, 0X10, 0XA3, 0X18, 0XE3, 0X19, 0X04, 0X18, 0XC3, + 0X18, 0XE4, 0X10, 0XC4, 0X10, 0XC3, 0X10, 0XE4, 0X21, 0X25, 0X18, 0XE4, + 0X21, 0X45, 0X10, 0XC4, 0X18, 0XE4, 0X52, 0X68, 0X49, 0XE5, 0X6B, 0X2B, + 0X6B, 0X2D, 0X83, 0XF0, 0X83, 0XCF, 0X73, 0X4C, 0X7B, 0X8D, 0X73, 0X8E, + 0X7C, 0X10, 0X6B, 0X2A, 0X6B, 0X69, 0X73, 0X8A, 0X73, 0X8A, 0X73, 0X2A, + 0X73, 0X6A, 0X6B, 0X8A, 0X73, 0X8A, 0X7B, 0XAC, 0X7B, 0X8B, 0X7B, 0XAC, + 0X7B, 0X8B, 0X7B, 0XCC, 0X7B, 0X8B, 0X73, 0X6B, 0X7B, 0X8C, 0X73, 0XAB, + 0X73, 0XAA, 0X73, 0XAA, 0X73, 0X6A, 0X73, 0X2A, 0X62, 0XC8, 0X62, 0XC7, + 0X52, 0X26, 0X5A, 0XA7, 0X73, 0XCC, 0X33, 0X0C, 0X6B, 0X29, 0X6B, 0X69, + 0X7B, 0XEB, 0X7C, 0X2C, 0X6B, 0X8A, 0X6B, 0X2A, 0X8C, 0X50, 0X84, 0X0F, + 0X73, 0XCE, 0X59, 0XE6, 0X39, 0X23, 0X29, 0X03, 0X5A, 0X05, 0X62, 0X25, + 0X62, 0X25, 0X62, 0X25, 0X62, 0X25, 0X62, 0X46, 0X49, 0XA4, 0X39, 0X64, + 0X49, 0X63, 0X51, 0XC5, 0X6A, 0X66, 0X6A, 0XE8, 0X62, 0X67, 0X5A, 0X27, + 0X52, 0X07, 0X62, 0XA8, 0X5A, 0X47, 0X52, 0X27, 0X5A, 0X27, 0X5A, 0X06, + 0X51, 0XC6, 0X51, 0XE6, 0X62, 0X05, 0X62, 0X26, 0X62, 0X26, 0X62, 0X05, + 0X51, 0XA5, 0X51, 0XC6, 0X49, 0XC6, 0X49, 0XA5, 0X41, 0X84, 0X49, 0XA4, + 0X41, 0X84, 0X59, 0XE5, 0X82, 0X67, 0X51, 0XA4, 0X39, 0X44, 0X31, 0X03, + 0X31, 0X03, 0X31, 0X03, 0X31, 0X03, 0X41, 0XA5, 0X29, 0X24, 0X29, 0X24, + 0X31, 0X65, 0X31, 0X45, 0X29, 0X04, 0X31, 0X03, 0X52, 0X06, 0X52, 0X06, + 0X49, 0X83, 0X49, 0X83, 0X51, 0XA4, 0X52, 0X06, 0X39, 0X23, 0X39, 0X23, + 0X31, 0X02, 0X49, 0XE6, 0X49, 0XC5, 0X49, 0XA4, 0X49, 0XA5, 0X31, 0X02, + 0X39, 0X64, 0X62, 0X88, 0X5A, 0X27, 0X29, 0XE8, 0X52, 0X68, 0X52, 0X06, + 0X62, 0X27, 0X52, 0X06, 0X49, 0XC5, 0X52, 0X06, 0X72, 0XA8, 0X52, 0X26, + 0X31, 0X03, 0X41, 0X64, 0X52, 0X06, 0X51, 0XE6, 0X51, 0XC5, 0X51, 0XC5, + 0X51, 0XC5, 0X51, 0XC5, 0X49, 0X84, 0X39, 0X44, 0X19, 0X04, 0X18, 0XE4, + 0X29, 0X66, 0X62, 0XCA, 0X62, 0XA9, 0X62, 0XA8, 0X31, 0X88, 0X29, 0XCA, + 0X29, 0X46, 0X29, 0X66, 0X3A, 0X2B, 0X4A, 0X6B, 0X39, 0XA7, 0X31, 0X05, + 0X31, 0X86, 0X2A, 0X48, 0X2A, 0X47, 0X2A, 0X28, 0X31, 0XE6, 0X29, 0X04, + 0X29, 0X26, 0X21, 0X25, 0X52, 0X48, 0X8B, 0XCD, 0X4A, 0X27, 0X52, 0X68, + 0X31, 0X85, 0X62, 0XA9, 0X62, 0XA9, 0X29, 0X03, 0X21, 0X46, 0X29, 0X68, + 0X29, 0X26, 0X42, 0X06, 0X6B, 0X8B, 0X52, 0XA8, 0X21, 0X04, 0X2B, 0X2C, + 0X29, 0X65, 0X22, 0X29, 0X1A, 0XCB, 0X41, 0X85, 0X5A, 0X67, 0X31, 0X23, + 0X39, 0XC7, 0X21, 0X46, 0X10, 0X82, 0X39, 0X44, 0X41, 0XA5, 0X49, 0XC5, + 0X5A, 0X27, 0X7A, 0XC9, 0X49, 0XE6, 0X5A, 0X47, 0X83, 0X0A, 0X7A, 0XE9, + 0X7A, 0XE9, 0X7A, 0XE9, 0X7A, 0XC9, 0X83, 0X0A, 0X62, 0X47, 0X21, 0X03, + 0X29, 0X03, 0X20, 0XE4, 0X21, 0X04, 0X20, 0XE4, 0X18, 0XC3, 0X21, 0X46, + 0X21, 0X25, 0X20, 0XE2, 0X10, 0X61, 0X10, 0XA2, 0X10, 0X82, 0X20, 0XE3, + 0X31, 0X44, 0X21, 0X23, 0X18, 0XE3, 0X18, 0XC3, 0X21, 0X04, 0X21, 0X24, + 0X19, 0X04, 0X08, 0XC3, 0X10, 0XC3, 0X10, 0XC3, 0X18, 0XC3, 0X10, 0X82, + 0X08, 0XA3, 0X08, 0X62, 0X10, 0XA2, 0X10, 0XE3, 0X10, 0XE3, 0X10, 0XE3, + 0X10, 0XC3, 0X10, 0X82, 0X10, 0X61, 0X21, 0X25, 0X52, 0XAC, 0X39, 0XC7, + 0X08, 0X61, 0X18, 0XC3, 0X18, 0XC3, 0X18, 0XC3, 0X18, 0XC3, 0X18, 0XC3, + 0X18, 0XE3, 0X21, 0X03, 0X18, 0XC3, 0X18, 0XC3, 0X18, 0XC3, 0X18, 0XA2, + 0X10, 0XC3, 0X18, 0XE3, 0X10, 0XA2, 0X08, 0X61, 0X10, 0X81, 0X10, 0XC2, + 0X10, 0XA2, 0X18, 0XE4, 0X18, 0XE3, 0X21, 0X04, 0X18, 0XE3, 0X19, 0X24, + 0X19, 0X05, 0X10, 0XA3, 0X10, 0XA2, 0X21, 0X04, 0X18, 0XC2, 0X21, 0X66, + 0X39, 0XA6, 0X31, 0X03, 0X10, 0X81, 0X19, 0X03, 0X31, 0X23, 0X49, 0XC5, + 0X49, 0XC6, 0X39, 0X84, 0X20, 0XE3, 0X28, 0XC3, 0X31, 0X24, 0X29, 0X44, + 0X39, 0XC7, 0X20, 0XE4, 0X18, 0XC3, 0X29, 0X03, 0X39, 0X44, 0X51, 0XE6, + 0X21, 0X03, 0X18, 0XC2, 0X29, 0X24, 0X29, 0X03, 0X31, 0XC7, 0X20, 0XE3, + 0X20, 0XC3, 0X39, 0X85, 0X39, 0X44, 0X20, 0XE3, 0X39, 0XE8, 0X29, 0X65, + 0X20, 0XA2, 0X28, 0XE2, 0X18, 0XC3, 0X31, 0X44, 0X39, 0X85, 0X31, 0X65, + 0X21, 0X03, 0X29, 0XA5, 0X21, 0XE5, 0X11, 0X23, 0X19, 0X65, 0X18, 0XC3, + 0X19, 0X25, 0X11, 0X05, 0X08, 0X62, 0X08, 0XA3, 0X19, 0X25, 0X21, 0X45, + 0X19, 0XA7, 0X09, 0X04, 0X09, 0X24, 0X08, 0XC3, 0X08, 0XC3, 0X11, 0X66, + 0X09, 0X04, 0X08, 0XE3, 0X09, 0X86, 0X09, 0X66, 0X19, 0X66, 0X19, 0X25, + 0X18, 0XE4, 0X18, 0XE4, 0X18, 0XE3, 0X18, 0XC2, 0X29, 0X03, 0X41, 0XA5, + 0X52, 0X06, 0X5A, 0X67, 0X5A, 0X67, 0X62, 0X46, 0X62, 0X26, 0X62, 0X26, + 0X62, 0X47, 0X62, 0X47, 0X62, 0X46, 0X7B, 0X4A, 0X82, 0XA6, 0X79, 0X81, + 0X69, 0XE4, 0X62, 0X65, 0X51, 0XE4, 0X51, 0XC5, 0X59, 0XE6, 0X39, 0XE6, + 0X31, 0XC6, 0X59, 0XC6, 0X51, 0XA6, 0X41, 0XA6, 0X51, 0XC6, 0X5A, 0X69, + 0X49, 0XC6, 0X62, 0X28, 0X9B, 0X2B, 0X6A, 0X48, 0X39, 0X65, 0X93, 0X4C, + 0X7A, 0XCA, 0X7A, 0XEA, 0X8B, 0X2C, 0X52, 0X49, 0X52, 0X69, 0X52, 0X29, + 0X49, 0X86, 0X49, 0XA5, 0X49, 0XC6, 0X52, 0X06, 0X5A, 0X07, 0X51, 0XC7, + 0X49, 0XA7, 0X49, 0XA6, 0X49, 0XA6, 0X51, 0XC6, 0X7B, 0X8F, 0X62, 0XAA, + 0X49, 0X64, 0X51, 0XA5, 0X5A, 0X48, 0X5A, 0X89, 0X5A, 0X89, 0X52, 0X08, + 0X49, 0X85, 0X41, 0X44, 0X31, 0X23, 0X49, 0XA5, 0X49, 0XA5, 0X4A, 0X47, + 0X41, 0XC5, 0X51, 0XE6, 0X6A, 0XC9, 0X62, 0XA9, 0X62, 0X88, 0X62, 0XA9, + 0X49, 0XE6, 0X31, 0X03, 0X39, 0X24, 0X39, 0X24, 0X41, 0X65, 0X51, 0XC6, + 0X62, 0X28, 0X2B, 0X4B, 0X1A, 0X26, 0X29, 0X65, 0X41, 0XC7, 0X5A, 0XCA, + 0X2A, 0X27, 0X3A, 0XEA, 0X6A, 0X88, 0X59, 0XA5, 0X42, 0X05, 0X63, 0X2A, + 0X7B, 0X8B, 0X5A, 0X88, 0X39, 0XE6, 0X63, 0X29, 0X6B, 0X8B, 0X6B, 0X8B, + 0X6B, 0XCF, 0X6B, 0X6B, 0X63, 0X4A, 0X6B, 0X8C, 0X4A, 0X47, 0X32, 0XEA, + 0X41, 0X65, 0X52, 0X28, 0X59, 0XE7, 0X59, 0X65, 0X49, 0X45, 0X32, 0X28, + 0X52, 0X28, 0X52, 0X29, 0X83, 0X0A, 0X6A, 0X88, 0X3A, 0X48, 0X63, 0X2A, + 0X63, 0X2B, 0X6B, 0X6C, 0X6B, 0X6C, 0X73, 0X6C, 0X5B, 0X2B, 0X5B, 0X09, + 0X52, 0X4A, 0X5A, 0X6A, 0X7B, 0X8B, 0X6A, 0XA7, 0X72, 0X27, 0X72, 0X8C, + 0X72, 0XEA, 0X83, 0X4A, 0X7B, 0X4B, 0X83, 0X6C, 0X83, 0X8C, 0X83, 0X6C, + 0X83, 0X4C, 0X83, 0X4C, 0X83, 0X4C, 0X8B, 0X8D, 0X7B, 0X29, 0X62, 0XA7, + 0X83, 0X6C, 0X83, 0X6C, 0X7B, 0X2A, 0X61, 0XA4, 0X79, 0X87, 0X9B, 0X2D, + 0XAB, 0X0E, 0XB2, 0XAE, 0X93, 0X8F, 0X83, 0X8C, 0X83, 0XD0, 0X83, 0XB0, + 0X69, 0XE8, 0X6A, 0X29, 0X8B, 0X4D, 0X83, 0X6F, 0XA3, 0XCE, 0XC5, 0X34, + 0X6A, 0XED, 0X7A, 0XEB, 0X62, 0X48, 0X93, 0X2E, 0XB3, 0XEF, 0XB3, 0XCE, + 0X9B, 0X2C, 0X3B, 0XD2, 0X73, 0X0D, 0XA2, 0XAA, 0X9A, 0XEB, 0X72, 0X49, + 0X41, 0X66, 0X83, 0X90, 0X93, 0X4C, 0X9B, 0XCF, 0X6A, 0XED, 0X6A, 0XCC, + 0X72, 0XEC, 0X7B, 0X0C, 0X7B, 0X2E, 0X62, 0XCC, 0X83, 0X4D, 0X6A, 0XA9, + 0X5A, 0X2B, 0X6A, 0XF0, 0X62, 0XAC, 0X62, 0XEE, 0X52, 0X4A, 0X39, 0X87, + 0X52, 0X2B, 0X4A, 0X09, 0X7A, 0XCC, 0X6A, 0XAE, 0X83, 0X92, 0X8B, 0XB0, + 0X6A, 0X8B, 0X83, 0XD3, 0X9C, 0X95, 0X7A, 0XAC, 0X7A, 0XCD, 0X9B, 0X6C, + 0X8B, 0X2D, 0X7A, 0X8B, 0X72, 0XAC, 0XAB, 0XEE, 0XBC, 0X4E, 0X69, 0XA8, + 0X61, 0XA9, 0X72, 0X2C, 0X6A, 0X0C, 0X9A, 0XCD, 0XC3, 0X8F, 0X7A, 0X4C, + 0X72, 0X0B, 0X72, 0X0B, 0X69, 0XEB, 0X82, 0X8D, 0XED, 0X14, 0XA3, 0X2F, + 0X69, 0XCB, 0X8A, 0X2B, 0X89, 0XCA, 0X61, 0X06, 0XA2, 0X8B, 0XBB, 0X2D, + 0XA2, 0XAD, 0X72, 0X0A, 0X3A, 0X09, 0X5A, 0X6B, 0X9A, 0XEE, 0X62, 0X8B, + 0X71, 0X69, 0X61, 0XB0, 0X51, 0X8D, 0X59, 0XF1, 0X52, 0X34, 0X59, 0XCF, + 0X69, 0XF1, 0X41, 0XAB, 0X41, 0X88, 0X41, 0XCB, 0X49, 0XCC, 0X4A, 0X2E, + 0X39, 0XAC, 0X31, 0X6A, 0X31, 0X69, 0X29, 0X27, 0X59, 0XED, 0X5A, 0X4C, + 0X73, 0XCF, 0X41, 0X8A, 0X39, 0X68, 0X41, 0XAA, 0X49, 0XCB, 0X29, 0X26, + 0X10, 0XC3, 0X19, 0X04, 0X10, 0XA2, 0X31, 0X25, 0X41, 0X67, 0X08, 0X61, + 0X08, 0X41, 0X18, 0XA2, 0X20, 0XE3, 0X20, 0XE3, 0X21, 0X04, 0X21, 0X04, + 0X20, 0XE3, 0X28, 0XE3, 0X18, 0XC3, 0X18, 0XE3, 0X18, 0XC2, 0X10, 0XC3, + 0X21, 0X44, 0X29, 0XC7, 0X32, 0X28, 0X29, 0XC7, 0X19, 0X04, 0X29, 0X86, + 0X29, 0X86, 0X10, 0XA2, 0X18, 0XA3, 0X18, 0XE4, 0X18, 0X83, 0X18, 0XE4, + 0X31, 0X25, 0X48, 0X63, 0X21, 0X25, 0X19, 0X46, 0X21, 0X25, 0X3A, 0X6C, + 0X53, 0X90, 0X29, 0XE9, 0X42, 0XCD, 0X42, 0XAD, 0X64, 0X13, 0X5B, 0XB1, + 0X42, 0XAD, 0X5C, 0X15, 0X5B, 0XD3, 0X3A, 0X6B, 0X53, 0XB2, 0X5B, 0XD4, + 0X5B, 0XB3, 0X5B, 0XF5, 0X3A, 0X8C, 0X31, 0XE8, 0X42, 0XAC, 0X3A, 0X6B, + 0X43, 0X2E, 0X43, 0X0E, 0X29, 0XE9, 0X74, 0XB6, 0X4B, 0X2E, 0X3A, 0X4A, + 0X3A, 0X6A, 0X3A, 0X8B, 0X32, 0X29, 0X21, 0X86, 0X4B, 0X30, 0X64, 0X14, + 0X52, 0XED, 0X73, 0X2A, 0X52, 0XED, 0X53, 0XB1, 0X4B, 0X0E, 0X52, 0XAB, + 0X52, 0XCC, 0X53, 0X2E, 0X29, 0XA7, 0X29, 0XC7, 0X29, 0XA6, 0X19, 0X05, + 0X18, 0XE4, 0X10, 0XA2, 0X10, 0XA2, 0X21, 0XA7, 0X21, 0X66, 0X29, 0X66, + 0X21, 0X86, 0X19, 0X04, 0X29, 0X66, 0X29, 0X45, 0X19, 0X25, 0X21, 0X25, + 0X20, 0XE4, 0X21, 0XA6, 0X29, 0XE7, 0X32, 0X28 }; + +#endif // ifdef USES_P128 + +#endif // ifndef PLUGINSTRUCTS_P128_DATA_STRUCT_H From 6a833f4918c57fbfc828928e075d219f9b4a381a Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 2 Jan 2022 17:11:57 +0100 Subject: [PATCH 002/161] [P128] Fix ESP32 issues, add config for GPIO pin (only ESP32) --- src/_P128_NeoPixelBusFX.ino | 55 ++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/_P128_NeoPixelBusFX.ino b/src/_P128_NeoPixelBusFX.ino index eb6abcbd3..d5f64ca6d 100644 --- a/src/_P128_NeoPixelBusFX.ino +++ b/src/_P128_NeoPixelBusFX.ino @@ -7,6 +7,8 @@ // ####################################################################################################### // Changelog: +// 2022-01-02, tonhuisman Fixed ESP32 related issues (conditional compilation, wrong stripe type) +// Add configuration for ESP32 GPIO pin // 2022-01-01, tonhuisman On request migrated from https://github.com/djcysmic/NeopixelBusFX to ESPEasy (that is an // extension from plugin _P124_NeoPixelBusFX.ini on the ESPEasyPluginPlayground) // - Adjusted to work combined with FastLED library (random8() issues) @@ -110,7 +112,7 @@ # include # define SPEED_MAX 50 -# define ARRAYSIZE 300 // Max LED Count +# define ARRAYSIZE 300 // Max LED Count // Choose your color order below: @@ -121,15 +123,13 @@ // # define BRG //A three element color in the order of Blue, Red, and then Green. // # define RBG //A three element color in the order of Red, Blue, and then Green. -# define NEOPIXEL_LIB NeoPixelBrightnessBus // Neopixel library type -# ifdef ESP32 -# define METHOD DotStarEsp32DmaHspiMethod // HSPI MOSI - use DotStarEsp32DmaHspiMethod (should also work on ESP32S2) -# elif ESP8266 -# ifdef METHOD -# undef METHOD -# endif // ifdef METHOD +# define NEOPIXEL_LIB NeoPixelBrightnessBus // Neopixel library type +# if defined(ESP32) +# define METHOD NeoEsp32Rmt1800KbpsMethod // RMT, user selected pin - use NeoEsp32RmtMethod (should also work on ESP32S2) +# endif // if defined(ESP32) +# if defined(ESP8266) # define METHOD NeoEsp8266Uart1800KbpsMethod // GPIO2 - use NeoEsp8266Uart0800KbpsMethod for GPIO1(TX) -# endif // ifdef ESP32 +# endif // if defined(ESP32) # if defined GRB # define FEATURE NeoGrbFeature @@ -248,8 +248,13 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) { case PLUGIN_DEVICE_ADD: { - Device[++deviceCount].Number = PLUGIN_ID_128; - Device[deviceCount].Type = DEVICE_TYPE_DUMMY; + Device[++deviceCount].Number = PLUGIN_ID_128; + # if defined(ESP32) + Device[deviceCount].Type = DEVICE_TYPE_SINGLE; + # endif // if defined(ESP32) + # if defined(ESP8266) + Device[deviceCount].Type = DEVICE_TYPE_DUMMY; + # endif // if defined(ESP8266) Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_QUAD; Device[deviceCount].Custom = true; Device[deviceCount].Ports = 0; @@ -280,16 +285,25 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) break; } + # ifdef ESP32 + case PLUGIN_SET_DEFAULTS: + { + PIN(0) = -1; // None + break; + } + # endif // ifdef ESP32 + case PLUGIN_WEBFORM_LOAD: { + addFormSubHeader(F("Actuator")); + # ifdef ESP8266 addRowLabel(F("")); - String message = F("Please connect stripe to "); + addHtml(F("Please connect stripe to GPIO2!")); + # endif // ifdef ESP8266 # ifdef ESP32 - message += F("HSPI MOSI!"); - # elif ESP8266 - message += F("GPIO2!"); + addRowLabel(formatGpioName_output("Stripe data")); + addPinSelect(PinSelectPurpose::Generic_output, F("taskdevicepin1"), PIN(0)); # endif // ifdef ESP32 - addHtml(message); addFormNumericBox(F("Led Count"), F("plugin_128_leds"), PCONFIG(0), 1, 999); success = true; break; @@ -299,7 +313,9 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) { PCONFIG(0) = getFormItemInt(F("plugin_128_leds")); - // Settings.TaskDevicePin1[event->TaskIndex] = getFormItemInt(F("taskdevicepin1")); + # ifdef ESP32 + PIN(0) = getFormItemInt(F("taskdevicepin1")); + # endif // ifdef ESP32 success = true; break; @@ -309,10 +325,11 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) { if (!Plugin_128_pixels) { # ifdef ESP8266 - Plugin_128_pixels = new NEOPIXEL_LIB(PCONFIG(0)); + Plugin_128_pixels = new NEOPIXEL_LIB(min(static_cast(PCONFIG(0)), static_cast(ARRAYSIZE))); # endif // ifdef ESP8266 # ifdef ESP32 - Plugin_128_pixels = new NEOPIXEL_LIB(PCONFIG(0)); + Plugin_128_pixels = new NEOPIXEL_LIB(min(static_cast(PCONFIG(0)), static_cast(ARRAYSIZE)), + PIN(0)); # endif // ifdef ESP32 Plugin_128_pixels->Begin(); // This initializes the NeoPixelBus library. } From 9e68cc9436c22f4a82c38af1c1ac61dd902e23cf Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 2 Jan 2022 22:03:03 +0100 Subject: [PATCH 003/161] [P128] Move all code & variables to Plugin_data_struct --- src/_P128_NeoPixelBusFX.ino | 1573 +------------------- src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/PluginStructs/P128_data_struct.cpp | 1462 ++++++++++++++++++ src/src/PluginStructs/P128_data_struct.h | 186 +++ 4 files changed, 1670 insertions(+), 1553 deletions(-) diff --git a/src/_P128_NeoPixelBusFX.ino b/src/_P128_NeoPixelBusFX.ino index d5f64ca6d..f7f0f746d 100644 --- a/src/_P128_NeoPixelBusFX.ino +++ b/src/_P128_NeoPixelBusFX.ino @@ -7,6 +7,7 @@ // ####################################################################################################### // Changelog: +// 2022-01-02, tonhuisman Move all code to Plugin_data_struct, with minor modifications (initialization, *char[] size) // 2022-01-02, tonhuisman Fixed ESP32 related issues (conditional compilation, wrong stripe type) // Add configuration for ESP32 GPIO pin // 2022-01-01, tonhuisman On request migrated from https://github.com/djcysmic/NeopixelBusFX to ESPEasy (that is an @@ -109,128 +110,6 @@ */ # include "src/PluginStructs/P128_data_struct.h" // includes faketv.h, the color pattern for FakeTV -# include - -# define SPEED_MAX 50 -# define ARRAYSIZE 300 // Max LED Count - -// Choose your color order below: - -# define GRB // should be standard - SK6812(grb), WS2811, and WS2812 -// # define GRBW //This is used for SK6812rgbw pixels that have the separate white led in them. -// # define RGB //some older pixels -// # define RGBW //A four element color in the order of Red, Green, Blue, and then White. A common four element format. -// # define BRG //A three element color in the order of Blue, Red, and then Green. -// # define RBG //A three element color in the order of Red, Blue, and then Green. - -# define NEOPIXEL_LIB NeoPixelBrightnessBus // Neopixel library type -# if defined(ESP32) -# define METHOD NeoEsp32Rmt1800KbpsMethod // RMT, user selected pin - use NeoEsp32RmtMethod (should also work on ESP32S2) -# endif // if defined(ESP32) -# if defined(ESP8266) -# define METHOD NeoEsp8266Uart1800KbpsMethod // GPIO2 - use NeoEsp8266Uart0800KbpsMethod for GPIO1(TX) -# endif // if defined(ESP32) - -# if defined GRB - # define FEATURE NeoGrbFeature -# elif defined GRBW - # define FEATURE NeoGrbwFeature -# elif defined RGB - # define FEATURE NeoRgbFeature -# elif defined RGBW - # define FEATURE NeoRgbwFeature -# elif defined BRG - # define FEATURE NeoBrgFeature -# elif defined RBG - # define FEATURE NeoRbgFeature -# else // if defined GRB - # define FEATURE NeoGrbFeature -# endif // if defined GRB - -# define numPixels (sizeof(ftv_colors) / sizeof(ftv_colors[0])) - -NEOPIXEL_LIB *Plugin_128_pixels = NULL; - -const float pi = 3.1415926535897932384626433832795; - -uint16_t pos, - color, - r_pixel, - startpixel, - endpixel, - difference, - fps = 50, - colorcount; - -# if defined(RGBW) || defined(GRBW) -RgbwColor rgb_target[ARRAYSIZE], - rgb_old[ARRAYSIZE], - rgb, rrggbb, - rgb_tick_b = HtmlColor(0x505050), - rgb_tick_s = HtmlColor(0x101010), - rgb_m = HtmlColor(0x00FF00), - rgb_h = HtmlColor(0x0000FF), - rgb_s = HtmlColor(0xFF0000); -# else // if defined(RGBW) || defined(GRBW) -RgbColor rgb_target[ARRAYSIZE], - rgb_old[ARRAYSIZE], - rgb, rrggbb, - rgb_tick_b = HtmlColor(0x505050), - rgb_tick_s = HtmlColor(0x101010), - rgb_m = HtmlColor(0x00FF00), - rgb_h = HtmlColor(0x0000FF), - rgb_s = HtmlColor(0xFF0000); -# endif // if defined(RGBW) || defined(GRBW) - -int16_t fadedelay = 20; - -uint16_t pixelCount = ARRAYSIZE; - -int8_t defaultspeed = 25, - rainbowspeed = 1, - speed = 25, - count = 1, - rev_intensity = 3; - -uint32_t _counter_mode_step = 0, - fadetime = 1000, - ftv_holdTime, - pixelNum; - -uint16_t ftv_pr = 0, ftv_pg = 0, ftv_pb = 0; // Prev R, G, B; -uint32_t ftv_totalTime, ftv_fadeTime, ftv_startTime, ftv_elapsed; -uint16_t ftv_nr, ftv_ng, ftv_nb, ftv_r, ftv_g, ftv_b, ftv_i, ftv_frac; -uint8_t ftv_hi, ftv_lo, ftv_r8, ftv_g8, ftv_b8; - -String colorStr, - backgroundcolorStr; - -bool gReverseDirection = false; -bool rgb_s_off = false; -bool fadeIn = false; - -byte cooling = 50, - sparking = 120, - brightness = 31; - -unsigned long counter20ms = 0, - starttime[ARRAYSIZE], - starttimerb, - maxtime = 0; - -enum modetype { - Off, On, Fade, ColorFade, Rainbow, Kitt, Comet, - Theatre, Scan, Dualscan, Twinkle, TwinkleFade, Sparkle, Fire, - FireFlicker, Wipe, Dualwipe, FakeTV, SimpleClock -}; - -const char *modeName[] = { - "off", "on", "fade", "colorfade", "rainbow", "kitt", "comet", - "theatre", "scan", "dualscan", "twinkle", "twinklefade", "sparkle", "fire", - "fireflicker", "wipe", "dualwipe", "faketv", "simpleclock" -}; - -modetype mode, savemode, lastmode; # define PLUGIN_128 # define PLUGIN_ID_128 128 @@ -323,1464 +202,54 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { - if (!Plugin_128_pixels) { - # ifdef ESP8266 - Plugin_128_pixels = new NEOPIXEL_LIB(min(static_cast(PCONFIG(0)), static_cast(ARRAYSIZE))); - # endif // ifdef ESP8266 - # ifdef ESP32 - Plugin_128_pixels = new NEOPIXEL_LIB(min(static_cast(PCONFIG(0)), static_cast(ARRAYSIZE)), - PIN(0)); - # endif // ifdef ESP32 - Plugin_128_pixels->Begin(); // This initializes the NeoPixelBus library. - } + initPluginTaskData(event->TaskIndex, + new (std::nothrow) P128_data_struct(PIN(0), PCONFIG(0))); + P128_data_struct *P128_data = static_cast(getPluginTaskData(event->TaskIndex)); - pixelCount = PCONFIG(0); - success = true; + if (nullptr == P128_data) { + return success; + } + success = true; break; } case PLUGIN_READ: // -------------------------------------------> { - // there is no need to read them, just use current values - UserVar[event->BaseVarIndex] = mode; - UserVar[event->BaseVarIndex + 1] = savemode; - UserVar[event->BaseVarIndex + 2] = fadetime; - UserVar[event->BaseVarIndex + 3] = fadedelay; + P128_data_struct *P128_data = static_cast(getPluginTaskData(event->TaskIndex)); - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - log = F("Lights: mode: "); - log += modeName[mode]; - log += F(" lastmode: "); - log += modeName[savemode]; - log += F(" fadetime: "); - log += (int)UserVar[event->BaseVarIndex + 2]; - log += F(" fadedelay: "); - log += (int)UserVar[event->BaseVarIndex + 3]; - addLog(LOG_LEVEL_INFO, log); + if (nullptr == P128_data) { + return success; } + success = P128_data->plugin_read(event); - success = true; break; } case PLUGIN_WRITE: { - String log = ""; - String command = parseString(string, 1); + P128_data_struct *P128_data = static_cast(getPluginTaskData(event->TaskIndex)); - if ((command == F("neopixelfx")) || (command == F("nfx"))) { - success = true; - String subCommand = parseString(string, 2); - - if (subCommand == F("fadetime")) { - fadetime = parseString(string, 3).toInt(); - } - - else if (subCommand == F("fadedelay")) { - fadedelay = parseString(string, 3).toInt(); - } - - else if (subCommand == F("speed")) { - defaultspeed = parseString(string, 3).toInt(); - speed = defaultspeed; - } - - else if (subCommand == F("bgcolor")) { - hex2rrggbb(parseString(string, 3)); - } - - else if (subCommand == F("count")) { - count = parseString(string, 3).toInt(); - } - - else if ((subCommand == F("on")) || (subCommand == F("off"))) { - fadetime = 1000; - fadedelay = 0; - - fadetime = (parseString(string, 3) == "") - ? fadetime - : parseString(string, 3).toInt(); - fadedelay = (parseString(string, 4) == "") - ? fadedelay - : parseString(string, 4).toInt(); - - for (int pixel = 0; pixel < pixelCount; pixel++) { - r_pixel = (fadedelay < 0) - ? pixelCount - pixel - 1 - : pixel; - - starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); - - if ((subCommand == F("on")) && (mode == Off)) { // switch on - rgb_target[pixel] = rgb_old[pixel]; - rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); - } else if (subCommand == F("off")) { // switch off - rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); - rgb_target[pixel] = RgbColor(0); - } - } - - if ((subCommand == F("on")) && (mode == Off)) { // switch on - mode = (savemode == On) ? Fade : savemode; - } else if (subCommand == F("off")) { // switch off - savemode = mode; - mode = Fade; - } - - maxtime = starttime[r_pixel] + (fadetime / 20); - } - - else if (subCommand == F("dim")) { - Plugin_128_pixels->SetBrightness(parseString(string, 3).toInt()); - } - - else if (subCommand == F("line")) { - mode = On; - - hex2rgb(parseString(string, 5)); - - for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { - Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); - } - } - - else if (subCommand == F("tick")) { - mode = On; - - hex2rgb(parseString(string, 4)); - - // for (int i = 0; i < pixelCount ; i = i + (pixelCount / parseString(string, 3).toInt())) { - for (int i = 0; i < parseString(string, 3).toInt(); i++) { - Plugin_128_pixels->SetPixelColor(i * pixelCount / parseString(string, 3).toInt(), rgb); - } - } - - else if (subCommand == F("one")) { - mode = On; - - uint16_t pixnum = parseString(string, 3).toInt() - 1; - hex2rgb(parseString(string, 4)); - - Plugin_128_pixels->SetPixelColor(pixnum, rgb); - } - - else if ((subCommand == F("fade")) || (subCommand == F("all")) || (subCommand == F("rgb"))) { - mode = Fade; - - if ((subCommand == F("all")) || (subCommand == F("rgb"))) { - fadedelay = 0; - } - - hex2rgb(parseString(string, 3)); - hex2rgb_pixel(parseString(string, 3)); - - fadetime = (parseString(string, 4) == "") - ? fadetime - : parseString(string, 4).toInt(); - fadedelay = (parseString(string, 5) == "") - ? fadedelay - : parseString(string, 5).toInt(); - - for (int pixel = 0; pixel < pixelCount; pixel++) { - r_pixel = (fadedelay < 0) - ? pixelCount - pixel - 1 - : pixel; - - starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); - - rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); - } - maxtime = starttime[r_pixel] + (fadetime / 20); - } - - else if (subCommand == F("hsv")) { - mode = Fade; - fadedelay = 0; - rgb = - RgbColor(HsbColor(parseString(string, 3).toFloat() / 360, parseString(string, 4).toFloat() / 100, - parseString(string, 5).toFloat() / 100)); - - colorStr = ""; - rgb.R < 16 ? colorStr = "0" : ""; - colorStr += formatToHex(rgb.R, {}); - rgb.G < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.G, {}); - rgb.B < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.B, {}); - - hex2rgb_pixel(colorStr); - - fadetime = (parseString(string, 6) == "") - ? fadetime - : parseString(string, 6).toInt(); - fadedelay = (parseString(string, 7) == "") - ? fadedelay - : parseString(string, 7).toInt(); - - for (int pixel = 0; pixel < pixelCount; pixel++) { - r_pixel = (fadedelay < 0) - ? pixelCount - pixel - 1 - : pixel; - - starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); - - rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); - } - maxtime = starttime[r_pixel] + (fadetime / 20); - } - - else if (subCommand == F("hsvone")) { - mode = On; - rgb = - RgbColor(HsbColor(parseString(string, 4).toFloat() / 360, parseString(string, 5).toFloat() / 100, - parseString(string, 6).toFloat() / 100)); - - colorStr = ""; - rgb.R < 16 ? colorStr = "0" : ""; - colorStr += formatToHex(rgb.R, {}); - rgb.G < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.G, {}); - rgb.B < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.B, {}); - - hex2rgb(colorStr); - uint16_t pixnum = parseString(string, 3).toInt() - 1; - Plugin_128_pixels->SetPixelColor(pixnum, rgb); - } - - else if (subCommand == F("hsvline")) { - mode = On; - - rgb = - RgbColor(HsbColor(parseString(string, 5).toFloat() / 360, parseString(string, 6).toFloat() / 100, - parseString(string, 7).toFloat() / 100)); - - colorStr = ""; - rgb.R < 16 ? colorStr = "0" : ""; - colorStr += formatToHex(rgb.R, {}); - rgb.G < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.G, {}); - rgb.B < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.B, {}); - - hex2rgb(colorStr); - - for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { - Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); - } - } - - else if (subCommand == F("rainbow")) { - fadeIn = (mode == Off) ? true : false; - mode = Rainbow; - starttimerb = counter20ms; - - rainbowspeed = (parseString(string, 3) == "") - ? speed - : parseString(string, 3).toInt(); - - fadetime = (parseString(string, 4) == "") - ? fadetime - : parseString(string, 4).toInt(); - } - - else if (subCommand == F("colorfade")) { - mode = ColorFade; - - hex2rgb(parseString(string, 3)); - - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } - - startpixel = (parseString(string, 5) == "") - ? 0 - : parseString(string, 5).toInt() - 1; - endpixel = (parseString(string, 6) == "") - ? pixelCount - 1 - : parseString(string, 6).toInt() - 1; - } - - else if (subCommand == F("kitt")) { - mode = Kitt; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - - speed = (parseString(string, 4) == "") - ? defaultspeed - : parseString(string, 4).toInt(); - } - - else if (subCommand == F("comet")) { - mode = Comet; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - - speed = (parseString(string, 4) == "") - ? defaultspeed - : parseString(string, 4).toInt(); - } - - else if (subCommand == F("theatre")) { - mode = Theatre; - - hex2rgb(parseString(string, 3)); - - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } - - count = (parseString(string, 5) == "") - ? count - : parseString(string, 5).toInt(); - - speed = (parseString(string, 6) == "") - ? defaultspeed - : parseString(string, 6).toInt(); - - for (int i = 0; i < pixelCount; i++) { - if ((i / count) % 2 == 0) { - Plugin_128_pixels->SetPixelColor(i, rgb); - } else { - Plugin_128_pixels->SetPixelColor(i, rrggbb); - } - } - } - - else if (subCommand == F("scan")) { - mode = Scan; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } - - speed = (parseString(string, 5) == "") - ? defaultspeed - : parseString(string, 5).toInt(); - } - - else if (subCommand == F("dualscan")) { - mode = Dualscan; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } - - speed = (parseString(string, 5) == "") - ? defaultspeed - : parseString(string, 5).toInt(); - } - - else if (subCommand == F("twinkle")) { - mode = Twinkle; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } - - speed = (parseString(string, 5) == "") - ? defaultspeed - : parseString(string, 5).toInt(); - } - - else if (subCommand == F("twinklefade")) { - mode = TwinkleFade; - - hex2rgb(parseString(string, 3)); - - count = (parseString(string, 4) == "") - ? count - : parseString(string, 4).toInt(); - - speed = (parseString(string, 5) == "") - ? defaultspeed - : parseString(string, 5).toInt(); - } - - else if (subCommand == F("sparkle")) { - mode = Sparkle; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - hex2rrggbb(parseString(string, 4)); - - speed = (parseString(string, 5) == "") - ? defaultspeed - : parseString(string, 5).toInt(); - } - - else if (subCommand == F("wipe")) { - mode = Wipe; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - - if (parseString(string, 4) != "") { - hex2rrggbb(parseString(string, 4)); - } else { - hex2rrggbb("000000"); - } - - speed = (parseString(string, 5) == "") - ? defaultspeed - : parseString(string, 5).toInt(); - } - - else if (subCommand == F("dualwipe")) { - mode = Dualwipe; - - _counter_mode_step = 0; - - hex2rgb(parseString(string, 3)); - - if (parseString(string, 4) != "") { - hex2rrggbb(parseString(string, 4)); - } else { - hex2rrggbb("000000"); - } - - speed = (parseString(string, 5) == "") - ? defaultspeed - : parseString(string, 5).toInt(); - } - - else if (subCommand == F("faketv")) { - mode = FakeTV; - _counter_mode_step = 0; - - randomSeed(analogRead(A0)); - pixelNum = random(numPixels); // Begin at random point - - startpixel = (parseString(string, 3) == "") - ? 0 - : parseString(string, 3).toInt() - 1; - endpixel = (parseString(string, 4) == "") - ? pixelCount - : parseString(string, 4).toInt(); - } - - else if (subCommand == F("fire")) { - mode = Fire; - - fps = (parseString(string, 3) == "") - ? fps - : parseString(string, 3).toInt(); - - fps = (fps == 0 || fps > 50) ? 50 : fps; - - brightness = (parseString(string, 4) == "") - ? brightness - : parseString(string, 4).toFloat(); - cooling = (parseString(string, 5) == "") - ? cooling - : parseString(string, 5).toFloat(); - sparking = (parseString(string, 6) == "") - ? sparking - : parseString(string, 6).toFloat(); - } - - else if (subCommand == F("fireflicker")) { - mode = FireFlicker; - - rev_intensity = (parseString(string, 3) == "") - ? rev_intensity - : parseString(string, 3).toInt(); - - speed = (parseString(string, 4) == "") - ? defaultspeed - : parseString(string, 4).toInt(); - } - - else if (subCommand == F("simpleclock")) { - mode = SimpleClock; - - # if defined(RGBW) || defined(GRBW) - - if (parseString(string, 3) != "") { - if (parseString(string, 3).length() <= 6) { - rgb_tick_s = - RgbwColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, - rgbStr2Num(parseString(string, 3))); - } else { - rgb_tick_s = - RgbwColor(rgbStr2Num(parseString(string, 3)) >> 24, - rgbStr2Num(parseString(string, 3)) >> 16, - rgbStr2Num(parseString(string, 3)) >> 8, - rgbStr2Num(parseString(string, 3))); - } - } - - if (parseString(string, 4) != "") { - if (parseString(string, 4).length() <= 6) { - rgb_tick_b = - RgbwColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, - rgbStr2Num(parseString(string, 4))); - } else { - rgb_tick_b = - RgbwColor(rgbStr2Num(parseString(string, 4)) >> 24, - rgbStr2Num(parseString(string, 4)) >> 16, - rgbStr2Num(parseString(string, 4)) >> 8, - rgbStr2Num(parseString(string, 4))); - } - } - - if (parseString(string, 5) != "") { - if (parseString(string, 5).length() <= 6) { - rgb_h = - RgbwColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, - rgbStr2Num(parseString(string, 5))); - } else { - rgb_h = - RgbwColor(rgbStr2Num(parseString(string, 5)) >> 24, - rgbStr2Num(parseString(string, 5)) >> 16, - rgbStr2Num(parseString(string, 5)) >> 8, - rgbStr2Num(parseString(string, 5))); - } - } - - if (parseString(string, 6) != "") { - if (parseString(string, 6).length() <= 6) { - rgb_m = - RgbwColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, - rgbStr2Num(parseString(string, 6))); - } else { - rgb_m = - RgbwColor(rgbStr2Num(parseString(string, 6)) >> 24, - rgbStr2Num(parseString(string, 6)) >> 16, - rgbStr2Num(parseString(string, 6)) >> 8, - rgbStr2Num(parseString(string, 6))); - } - } - - if (parseString(string, 7) != "") { - if (parseString(string, 7) == "off") { - rgb_s_off = true; - } else if (parseString(string, 7).length() <= 6) { - rgb_s_off = false; - rgb_s = - RgbwColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, - rgbStr2Num(parseString(string, 7))); - } else { - rgb_s_off = false; - rgb_s = - RgbwColor(rgbStr2Num(parseString(string, 7)) >> 24, - rgbStr2Num(parseString(string, 7)) >> 16, - rgbStr2Num(parseString(string, 7)) >> 8, - rgbStr2Num(parseString(string, 7))); - } - } - - if (parseString(string, 8) != "") { - hex2rrggbb(parseString(string, 8)); - } - - # else // if defined(RGBW) || defined(GRBW) - - rgb_tick_s = (parseString(string, 3) == "") - ? rgb_tick_s - : RgbColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, rgbStr2Num(parseString(string, 3))); - rgb_tick_b = (parseString(string, 4) == "") - ? rgb_tick_b - : RgbColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, rgbStr2Num(parseString(string, 4))); - rgb_h = (parseString(string, 5) == "") - ? rgb_h - : RgbColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, rgbStr2Num(parseString(string, 5))); - rgb_m = (parseString(string, 6) == "") - ? rgb_m - : RgbColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, rgbStr2Num(parseString(string, 6))); - - if (parseString(string, 7) != "") { - if (parseString(string, 7) == "off") { - rgb_s_off = true; - } else { - rgb_s_off = false; - rgb_s = - RgbColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, - rgbStr2Num(parseString(string, 7))); - } - } - - if (parseString(string, 8) != "") { hex2rrggbb(parseString(string, 8)); } - - # endif // if defined(RGBW) || defined(GRBW) - } - - else if (subCommand == F("stop")) { - mode = On; - } - - else if (subCommand == F("statusrequest")) {} - - else if ((subCommand != F("all")) && (subCommand != F("line")) - && (subCommand != F("one")) && (subCommand != F("fade")) - && (subCommand != F("dim")) && (subCommand != F("fadetime")) - && (subCommand != F("speed")) && (subCommand != F("fadedelay")) - && (subCommand != F("count")) && (subCommand != F("bgcolor")) - && (subCommand != F("on")) && (subCommand != F("off")) - && (subCommand != F("rgb")) && (subCommand != F("rainbow")) - && (subCommand != F("kitt")) && (subCommand != F("comet")) - && (subCommand != F("theatre")) && (subCommand != F("scan")) - && (subCommand != F("dualscan")) && (subCommand != F("twinkle")) - && (subCommand != F("sparkle")) && (subCommand != F("fire")) - && (subCommand != F("fireflicker")) && (subCommand != F("hsvone")) - && (subCommand != F("hsv")) && (subCommand != F("hsvline")) - && (subCommand != F("twinklefade")) && (subCommand != F("stop")) - && (subCommand != F("wipe")) && (subCommand != F("dualwipe")) - && (subCommand != F("colorfade")) && (subCommand != F("simpleclock")) - && (subCommand != F("faketv")) && (subCommand != F("statusrequest"))) { - log = F("NeoPixelBus: unknown subcommand: "); - log += subCommand; - addLog(LOG_LEVEL_INFO, log); - - String json; - printToWebJSON = true; - json += F("{\n"); - json += F("\"plugin\": \"128\",\n"); - json += F("\"log\": \""); - json += F("NeoPixelBus: unknown command: "); - json += subCommand; - json += F("\"\n"); - json += F("}\n"); - - // event->Source=EventValueSource::Enum::VALUE_SOURCE_HTTP; - SendStatus(event, json); // send http response to controller (JSON format) - printToWeb = false; - } - NeoPixelSendStatus(event); - } // command neopixel - - if (speed == 0) { mode = On; // speed = 0 = stop mode + if (nullptr == P128_data) { + return success; } - speed = (speed > SPEED_MAX || speed < -SPEED_MAX) ? defaultspeed : speed; // avoid invalid values - fadetime = (fadetime <= 0) ? 20 : fadetime; + success = P128_data->plugin_write(event, string); break; } case PLUGIN_FIFTY_PER_SECOND: { - counter20ms++; - lastmode = mode; + P128_data_struct *P128_data = static_cast(getPluginTaskData(event->TaskIndex)); - switch (mode) { - case Fade: - fade(); - break; - - case ColorFade: - colorfade(); - break; - - case Rainbow: - rainbow(); - break; - - case Kitt: - kitt(); - break; - - case Comet: - comet(); - break; - - case Theatre: - theatre(); - break; - - case Scan: - scan(); - break; - - case Dualscan: - dualscan(); - break; - - case Twinkle: - twinkle(); - break; - - case TwinkleFade: - twinklefade(); - break; - - case Sparkle: - sparkle(); - break; - - case Fire: - fire(); - break; - - case FireFlicker: - fire_flicker(); - break; - - case Wipe: - wipe(); - break; - - case Dualwipe: - dualwipe(); - break; - - case FakeTV: - faketv(); - break; - - case SimpleClock: - Plugin_128_simpleclock(); - break; - - default: - break; - } // switch mode - - Plugin_128_pixels->Show(); - - if (mode != lastmode) { - String log = ""; - log = F("NeoPixelBus: Mode Change: "); - log += modeName[mode]; - addLog(LOG_LEVEL_INFO, log); - NeoPixelSendStatus(event); + if (nullptr == P128_data) { + return success; } - success = true; + success = P128_data->plugin_fifty_per_second(event); + break; } } return success; } -void fade(void) { - for (int pixel = 0; pixel < pixelCount; pixel++) { - long zaehler = 20 * (counter20ms - starttime[pixel]); - float progress = (float)zaehler / (float)fadetime; - progress = (progress < 0) ? 0 : progress; - progress = (progress > 1) ? 1 : progress; - - # if defined(RGBW) || defined(GRBW) - RgbwColor updatedColor = RgbwColor::LinearBlend( - rgb_old[pixel], rgb_target[pixel], - progress); - # else // if defined(RGBW) || defined(GRBW) - RgbColor updatedColor = RgbColor::LinearBlend( - rgb_old[pixel], rgb_target[pixel], - progress); - # endif // if defined(RGBW) || defined(GRBW) - - if ((counter20ms > maxtime) && (Plugin_128_pixels->GetPixelColor(pixel).CalculateBrightness() == 0)) { - mode = Off; - } else if (counter20ms > maxtime) { - mode = On; - } - - Plugin_128_pixels->SetPixelColor(pixel, updatedColor); - } -} - -void colorfade(void) { - float progress = 0; - - difference = (endpixel - startpixel + pixelCount) % pixelCount; - - for (uint16_t i = 0; i <= difference; i++) - { - progress = (float)i / (difference - 1); - progress = (progress >= 1) ? 1 : progress; - progress = (progress <= 0) ? 0 : progress; - - # if defined(RGBW) || defined(GRBW) - RgbwColor updatedColor = RgbwColor::LinearBlend( - rgb, rrggbb, - progress); - # else // if defined(RGBW) || defined(GRBW) - RgbColor updatedColor = RgbColor::LinearBlend( - rgb, rrggbb, - progress); - # endif // if defined(RGBW) || defined(GRBW) - - Plugin_128_pixels->SetPixelColor((i + startpixel) % pixelCount, updatedColor); - } - mode = On; -} - -void wipe(void) { - if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) { - if (speed > 0) { - Plugin_128_pixels->SetPixelColor(_counter_mode_step, rrggbb); - - if (_counter_mode_step > 0) { Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); } - } else { - Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step - 1, rrggbb); - - if (_counter_mode_step > 0) { Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step, rgb); } - } - - if (_counter_mode_step == pixelCount) { mode = On; } - _counter_mode_step++; - } -} - -void dualwipe(void) { - if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) { - if (speed > 0) { - int i = _counter_mode_step - pixelCount; - i = abs(i); - Plugin_128_pixels->SetPixelColor(_counter_mode_step, rrggbb); - Plugin_128_pixels->SetPixelColor(i, rgb); - - if (_counter_mode_step > 0) { - Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); - Plugin_128_pixels->SetPixelColor(i - 1, rrggbb); - } - } else { - int i = (pixelCount / 2) - _counter_mode_step; - i = abs(i); - Plugin_128_pixels->SetPixelColor(_counter_mode_step + (pixelCount / 2), rrggbb); - Plugin_128_pixels->SetPixelColor(i, rgb); - - if (_counter_mode_step > 0) { - Plugin_128_pixels->SetPixelColor(_counter_mode_step + (pixelCount / 2) - 1, rgb); - Plugin_128_pixels->SetPixelColor(i - 1, rrggbb); - } - } - - if (_counter_mode_step >= pixelCount / 2) { - mode = On; - Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); - } - _counter_mode_step++; - } -} - -void faketv(void) { - if (counter20ms >= ftv_holdTime) { - difference = abs(endpixel - startpixel); - - if (ftv_elapsed >= ftv_fadeTime) { - // Read next 16-bit (5/6/5) color - ftv_hi = pgm_read_byte(&ftv_colors[pixelNum * 2]); - ftv_lo = pgm_read_byte(&ftv_colors[pixelNum * 2 + 1]); - - if (++pixelNum >= numPixels) { pixelNum = 0; } - - // Expand to 24-bit (8/8/8) - ftv_r8 = (ftv_hi & 0xF8) | (ftv_hi >> 5); - ftv_g8 = (ftv_hi << 5) | ((ftv_lo & 0xE0) >> 3) | ((ftv_hi & 0x06) >> 1); - ftv_b8 = (ftv_lo << 3) | ((ftv_lo & 0x1F) >> 2); - - // Apply gamma correction, further expand to 16/16/16 - ftv_nr = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_r8]) * 257; // New R/G/B - ftv_ng = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_g8]) * 257; - ftv_nb = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_b8]) * 257; - - ftv_totalTime = random(12, 125); // Semi-random pixel-to-pixel time - ftv_fadeTime = random(0, ftv_totalTime); // Pixel-to-pixel transition time - - if (random(10) < 3) { ftv_fadeTime = 0; // Force scene cut 30% of time - } - ftv_holdTime = counter20ms + ftv_totalTime - ftv_fadeTime; // Non-transition time - ftv_startTime = counter20ms; - } - - ftv_elapsed = counter20ms - ftv_startTime; - - if (ftv_fadeTime) { - ftv_r = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pr, ftv_nr); // 16-bit interp - ftv_g = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pg, ftv_ng); - ftv_b = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pb, ftv_nb); - } else { // Avoid divide-by-ftv_fraczero in map() - ftv_r = ftv_nr; - ftv_g = ftv_ng; - ftv_b = ftv_nb; - } - - for (ftv_i = 0; ftv_i < difference; ftv_i++) { - ftv_r8 = ftv_r >> 8; // Quantize to 8-bit - ftv_g8 = ftv_g >> 8; - ftv_b8 = ftv_b >> 8; - ftv_frac = (ftv_i << 16) / difference; // LED index scaled to 0-65535 (16Bit) - - if ((ftv_r8 < 255) && ((ftv_r & 0xFF) >= ftv_frac)) { ftv_r8++; // Boost some fraction - } - - if ((ftv_g8 < 255) && ((ftv_g & 0xFF) >= ftv_frac)) { ftv_g8++; // of LEDs to handle - } - - if ((ftv_b8 < 255) && ((ftv_b & 0xFF) >= ftv_frac)) { ftv_b8++; // interp > 8bit - } - Plugin_128_pixels->SetPixelColor(ftv_i + startpixel, RgbColor(ftv_r8, ftv_g8, ftv_b8)); - } - - ftv_pr = ftv_nr; // Prev RGB = new RGB - ftv_pg = ftv_ng; - ftv_pb = ftv_nb; - } -} - -/* - * Cycles a rainbow over the entire string of LEDs. - */ -void rainbow(void) { - long zaehler = 20 * (counter20ms - starttimerb); - float progress = (float)zaehler / (float)fadetime; - - if (fadeIn == true) { - Plugin_128_pixels->SetBrightness(progress * 255); - fadeIn = (progress == 1) ? false : true; - } - - for (int i = 0; i < pixelCount; i++) - { - uint8_t r1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255) >> 16); - uint8_t g1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255) >> 8); - uint8_t b1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255)); - Plugin_128_pixels->SetPixelColor(i, RgbColor(r1, g1, b1)); - } - mode = (rainbowspeed == 0) ? On : Rainbow; -} - -/* - * Put a value 0 to 255 in to get a color value. - * The colours are a transition r -> g -> b -> back to r - * Inspired by the Adafruit examples. - */ -uint32_t Wheel(uint8_t pos) { - pos = 255 - pos; - - if (pos < 85) { - return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); - } else if (pos < 170) { - pos -= 85; - return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3); - } else { - pos -= 170; - return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0); - } -} - -// Larson Scanner K.I.T.T. -void kitt(void) { - if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) - { - for (uint16_t i = 0; i < pixelCount; i++) { - # if defined(RGBW) || defined(GRBW) - RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(i); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - px_rgb.W = px_rgb.W >> 1; - - # else // if defined(RGBW) || defined(GRBW) - - RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(i); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - # endif // if defined(RGBW) || defined(GRBW) - - Plugin_128_pixels->SetPixelColor(i, px_rgb); - } - - uint16_t pos = 0; - - if (_counter_mode_step < pixelCount) { - pos = _counter_mode_step; - } else { - pos = (pixelCount * 2) - _counter_mode_step - 2; - } - - Plugin_128_pixels->SetPixelColor(pos, rgb); - - _counter_mode_step = (_counter_mode_step + 1) % ((pixelCount * 2) - 2); - } -} - -// Firing comets from one end. -void comet(void) { - if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) - { - for (uint16_t i = 0; i < pixelCount; i++) { - if (speed > 0) { - # if defined(RGBW) || defined(GRBW) - RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(i); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - px_rgb.W = px_rgb.W >> 1; - - # else // if defined(RGBW) || defined(GRBW) - - RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(i); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - # endif // if defined(RGBW) || defined(GRBW) - - Plugin_128_pixels->SetPixelColor(i, px_rgb); - } else { - # if defined(RGBW) || defined(GRBW) - RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - px_rgb.W = px_rgb.W >> 1; - - # else // if defined(RGBW) || defined(GRBW) - - RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - # endif // if defined(RGBW) || defined(GRBW) - - Plugin_128_pixels->SetPixelColor(pixelCount - i - 1, px_rgb); - } - } - - if (speed > 0) { - Plugin_128_pixels->SetPixelColor(_counter_mode_step, rgb); - } else { - Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step - 1, rgb); - } - - _counter_mode_step = (_counter_mode_step + 1) % pixelCount; - } -} - -// Theatre lights -void theatre(void) { - if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) - { - if (speed > 0) { - Plugin_128_pixels->RotateLeft(1, 0, (pixelCount / count) * count - 1); - } else { - Plugin_128_pixels->RotateRight(1, 0, (pixelCount / count) * count - 1); - } - } -} - -/* - * Runs a single pixel back and forth. - */ -void scan(void) { - if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) - { - if (_counter_mode_step > uint16_t((pixelCount * 2) - 2)) { - _counter_mode_step = 0; - } - _counter_mode_step++; - - int i = _counter_mode_step - (pixelCount - 1); - i = abs(i); - - // Plugin_128_pixels->ClearTo(rrggbb); - for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } - Plugin_128_pixels->SetPixelColor(abs(i), rgb); - } -} - -/* - * Runs two pixel back and forth in opposite directions. - */ -void dualscan(void) { - if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) { - if (_counter_mode_step > uint16_t((pixelCount * 2) - 2)) { - _counter_mode_step = 0; - } - - _counter_mode_step++; - - int i = _counter_mode_step - (pixelCount - 1); - i = abs(i); - - // Plugin_128_pixels->ClearTo(rrggbb); - for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } - Plugin_128_pixels->SetPixelColor(abs(i), rgb); - Plugin_128_pixels->SetPixelColor(pixelCount - (i + 1), rgb); - } -} - -/* - * Blink several LEDs on, reset, repeat. - * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ - */ -void twinkle(void) { - if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) - { - if (_counter_mode_step == 0) { - // Plugin_128_pixels->ClearTo(rrggbb); - for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } - uint16_t min_leds = _max(1, pixelCount / 5); // make sure, at least one LED is on - uint16_t max_leds = _max(1, pixelCount / 2); // make sure, at least one LED is on - _counter_mode_step = random(min_leds, max_leds); - } - - Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); - - _counter_mode_step--; - } -} - -/* - * Blink several LEDs on, fading out. - */ -void twinklefade(void) { - if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) - { - for (uint16_t i = 0; i < pixelCount; i++) { - # if defined(RGBW) || defined(GRBW) - RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - px_rgb.W = px_rgb.W >> 1; - - # else // if defined(RGBW) || defined(GRBW) - - RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); - - // fade out (divide by 2) - px_rgb.R = px_rgb.R >> 1; - px_rgb.G = px_rgb.G >> 1; - px_rgb.B = px_rgb.B >> 1; - # endif // if defined(RGBW) || defined(GRBW) - - Plugin_128_pixels->SetPixelColor(i, px_rgb); - } - - if (random(count) < 50) { - Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); - } - } -} - -/* - * Blinks one LED at a time. - * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ - */ -void sparkle(void) { - if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) - { - // Plugin_128_pixels->ClearTo(rrggbb); - for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } - Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); - } -} - -// Fire -unsigned long fireTimer; -RgbColor leds[ARRAYSIZE]; - -void fire(void) { - if (counter20ms > fireTimer + 50 / fps) { - fireTimer = counter20ms; - Fire2012(); - RgbColor pixel; - - for (int i = 0; i < pixelCount; i++) { - pixel = leds[i]; - pixel = RgbColor::LinearBlend(pixel, RgbColor(0, 0, 0), (255 - brightness) / 255.0); - Plugin_128_pixels->SetPixelColor(i, pixel); - } - } -} - -/// random number seed -uint16_t rand16seed; // = RAND16_SEED; - -/// Generate an 8-bit random number -uint8_t random8() { - rand16seed = (rand16seed * ((uint16_t)(2053))) + ((uint16_t)(13849)); - - // return the sum of the high and low bytes, for better - // mixing and non-sequential correlation - return (uint8_t)(((uint8_t)(rand16seed & 0xFF)) + - ((uint8_t)(rand16seed >> 8))); -} - -/// Generate an 8-bit random number between 0 and lim -/// @param lim the upper bound for the result -uint8_t random8(uint8_t lim) { - uint8_t r = random8(); - - r = (r * lim) >> 8; - return r; -} - -/// Generate an 8-bit random number in the given range -/// @param min the lower bound for the random number -/// @param lim the upper bound for the random number -uint8_t random8(uint8_t min, uint8_t lim) { - uint8_t delta = lim - min; - uint8_t r = random8(delta) + min; - - return r; -} - -/// subtract one byte from another, saturating at 0x00 -/// @returns i - j with a floor of 0 -uint8_t qsub8(uint8_t i, uint8_t j) { - int t = i - j; - - if (t < 0) { t = 0; } - return t; -} - -/// add one byte to another, saturating at 0xFF -/// @param i - first byte to add -/// @param j - second byte to add -/// @returns the sum of i & j, capped at 0xFF -uint8_t qadd8(uint8_t i, uint8_t j) { - unsigned int t = i + j; - - if (t > 255) { t = 255; } - return t; -} - -/// The "video" version of scale8 guarantees that the output will -/// be only be zero if one or both of the inputs are zero. If both -/// inputs are non-zero, the output is guaranteed to be non-zero. -/// This makes for better 'video'/LED dimming, at the cost of -/// several additional cycles. -uint8_t scale8_video(uint8_t i, uint8_t scale) { - uint8_t j = (((int)i * (int)scale) >> 8) + ((i && scale) ? 1 : 0); - - // uint8_t nonzeroscale = (scale != 0) ? 1 : 0; - // uint8_t j = (i == 0) ? 0 : (((int)i * (int)(scale) ) >> 8) + nonzeroscale; - return j; -} - -void Fire2012(void) { - // Array of temperature readings at each simulation cell - static byte heat[ARRAYSIZE]; - - // Step 1. Cool down every cell a little - for (int i = 0; i < pixelCount; i++) { - heat[i] = qsub8(heat[i], random8(0, ((cooling * 10) / pixelCount) + 2)); - } - - // Step 2. Heat from each cell drifts 'up' and diffuses a little - for (int k = pixelCount - 1; k >= 2; k--) { - heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; - } - - // Step 3. Randomly ignite new 'sparks' of heat near the bottom - if (random8() < sparking) { - int y = random8(7); - heat[y] = qadd8(heat[y], random8(160, 255)); - } - - // Step 4. Map from heat cells to LED colors - for (int j = 0; j < pixelCount; j++) { - RgbColor heatcolor; - - // Scale 'heat' down from 0-255 to 0-191, - // which can then be easily divided into three - // equal 'thirds' of 64 units each. - uint8_t t192 = scale8_video(heat[j], 191); - - // calculate a value that ramps up from - // zero to 255 in each 'third' of the scale. - uint8_t heatramp = t192 & 0x3F; // 0..63 - heatramp <<= 2; // scale up to 0..252 - - // now figure out which third of the spectrum we're in: - if (t192 & 0x80) { - // we're in the hottest third - heatcolor.R = 255; // full red - heatcolor.G = 255; // full green - heatcolor.B = heatramp; // ramp up blue - } else if (t192 & 0x40) { - // we're in the middle third - heatcolor.R = 255; // full red - heatcolor.G = heatramp; // ramp up green - heatcolor.B = 0; // no blue - } else { - // we're in the coolest third - heatcolor.R = heatramp; // ramp up red - heatcolor.G = 0; // no green - heatcolor.B = 0; // no blue - } - - int pixelnumber; - - if (gReverseDirection) { - pixelnumber = (pixelCount - 1) - j; - } else { - pixelnumber = j; - } - leds[pixelnumber] = heatcolor; - } -} - -/* - * Fire flicker function - */ -void fire_flicker() { - if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) - { - byte w = 0; // (SEGMENT.colors[0] >> 24) & 0xFF; - byte r = 255; // (SEGMENT.colors[0] >> 16) & 0xFF; - byte g = 96; // (SEGMENT.colors[0] >> 8) & 0xFF; - byte b = 12; // (SEGMENT.colors[0] & 0xFF); - byte lum = max(w, max(r, max(g, b))) / rev_intensity; - - for (uint16_t i = 0; i <= numPixels - 1; i++) { - int flicker = random8(lum); - - # if defined(RGBW) || defined(GRBW) - Plugin_128_pixels->SetPixelColor(i, RgbwColor(max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0))); - # else // if defined(RGBW) || defined(GRBW) - Plugin_128_pixels->SetPixelColor(i, RgbColor(max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0))); - # endif // if defined(RGBW) || defined(GRBW) - } - } -} - -void Plugin_128_simpleclock() { - byte Hours = node_time.hour() % 12; - byte Minutes = node_time.minute(); - byte Seconds = node_time.second(); - byte big_tick = 15; - byte small_tick = 5; - - // hack for sub-second calculations.... reset when first time new second begins.. - if (cooling != Seconds) { maxtime = counter20ms; } - cooling = Seconds; - Plugin_128_pixels->ClearTo(rrggbb); - - for (int i = 0; i < (60 / small_tick); i++) { - if (i % (big_tick / small_tick) == 0) { Plugin_128_pixels->SetPixelColor((i * pixelCount * small_tick / 60) % pixelCount, rgb_tick_b); } - else { Plugin_128_pixels->SetPixelColor((i * pixelCount * small_tick / 60) % pixelCount, rgb_tick_s); } - } - - - for (int i = 0; i < pixelCount; i++) { - if (round((((float)Seconds + ((float)counter20ms - (float)maxtime) / 50.0) * (float)pixelCount) / 60.0) == i) { - if (rgb_s_off == false) { - Plugin_128_pixels->SetPixelColor(i, rgb_s); - } - } - else if (round((((float)Minutes * 60.0) + (float)Seconds) / 60.0 * (float)pixelCount / 60.0) == i) { - Plugin_128_pixels->SetPixelColor(i, rgb_m); - } - else if (round(((float)Hours + (float)Minutes / 60) * (float)pixelCount / 12.0) == i) { - Plugin_128_pixels->SetPixelColor(i, rgb_h); - Plugin_128_pixels->SetPixelColor((i + 1) % pixelCount, rgb_h); - Plugin_128_pixels->SetPixelColor((i - 1 + pixelCount) % pixelCount, rgb_h); - } - } -} - -uint32_t rgbStr2Num(String rgbStr) { - uint32_t rgbDec = (int)strtoul(&rgbStr[0], NULL, 16); - - return rgbDec; -} - -void hex2rgb(String hexcolor) { - colorStr = hexcolor; - # if defined(RGBW) || defined(GRBW) - hexcolor.length() <= 6 - ? rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) - : rgb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); - # else // if defined(RGBW) || defined(GRBW) - rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); - # endif // if defined(RGBW) || defined(GRBW) -} - -void hex2rrggbb(String hexcolor) { - backgroundcolorStr = hexcolor; - # if defined(RGBW) || defined(GRBW) - hexcolor.length() <= 6 - ? rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) - : rrggbb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); - # else // if defined(RGBW) || defined(GRBW) - rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); - # endif // if defined(RGBW) || defined(GRBW) -} - -void hex2rgb_pixel(String hexcolor) { - colorStr = hexcolor; - - for (int i = 0; i < pixelCount; i++) { - # if defined(RGBW) || defined(GRBW) - hexcolor.length() <= 6 - ? rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) - : rgb_target[i] = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); - # else // if defined(RGBW) || defined(GRBW) - rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); - # endif // if defined(RGBW) || defined(GRBW) - } -} - -// --------------------------------------------------------------------------------- -// ------------------------------ JsonResponse ------------------------------------- -// --------------------------------------------------------------------------------- -void NeoPixelSendStatus(struct EventStruct *eventSource) { - String log = String(F("NeoPixelBusFX: Set ")) + rgb.R - + String(F("/")) + rgb.G + String(F("/")) + rgb.B; - - addLog(LOG_LEVEL_INFO, log); - - String json; - - printToWebJSON = true; - json += F("{\n"); - json += F("\"plugin\": \"128"); - json += F("\",\n\"mode\": \""); - json += modeName[mode]; - json += F("\",\n\"lastmode\": \""); - json += modeName[savemode]; - json += F("\",\n\"fadetime\": \""); - json += fadetime; - json += F("\",\n\"fadedelay\": \""); - json += fadedelay; - json += F("\",\n\"dim\": \""); - json += Plugin_128_pixels->GetBrightness(); - json += F("\",\n\"rgb\": \""); - json += colorStr; - json += F("\",\n\"hue\": \""); - json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).H * 360), 0); - json += F("\",\n\"saturation\": \""); - json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).S * 100), 0); - json += F("\",\n\"brightness\": \""); - json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).B * 100), 0); - json += F("\",\n\"bgcolor\": \""); - json += backgroundcolorStr; - json += F("\",\n\"count\": \""); - json += count; - json += F("\",\n\"speed\": \""); - json += speed; - json += F("\",\n\"pixelcount\": \""); - json += pixelCount; - json += F("\"\n}\n"); - SendStatus(eventSource, json); // send http response to controller (JSON format) - printToWeb = false; -} - #endif // USES_P128 diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 488bec10e..bc61fff57 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1455,7 +1455,7 @@ To create/register a plugin, you have to : #define USES_P127 // #endif #ifndef USES_P128 - #define USES_P128 // NeoPixelBusFX, (not yet working on 'plain' ESP32) + #define USES_P128 // NeoPixelBusFX #endif #ifndef USES_P129 #define USES_P129 // diff --git a/src/src/PluginStructs/P128_data_struct.cpp b/src/src/PluginStructs/P128_data_struct.cpp index f84c2fa7b..e7a89fc45 100644 --- a/src/src/PluginStructs/P128_data_struct.cpp +++ b/src/src/PluginStructs/P128_data_struct.cpp @@ -5,4 +5,1466 @@ // TODO: implementation code +//***************************************************************/ +// +//***************************************************************/ +P128_data_struct::P128_data_struct(int8_t _gpioPin, + uint16_t _pixelCount) + : gpioPin(_gpioPin), pixelCount(_pixelCount) { + if (!Plugin_128_pixels) { + # ifdef ESP8266 + Plugin_128_pixels = new NEOPIXEL_LIB(min(pixelCount, static_cast(ARRAYSIZE))); + # endif // ifdef ESP8266 + # ifdef ESP32 + Plugin_128_pixels = new NEOPIXEL_LIB(min(pixelCount, static_cast(ARRAYSIZE)), + _gpioPin); + # endif // ifdef ESP32 + Plugin_128_pixels->Begin(); // This initializes the NeoPixelBus library. + } + + // pixelCount = _pixelCount; +} + +//***************************************************************/ +// Destructor +//***************************************************************/ +P128_data_struct::~P128_data_struct() { + if (Plugin_128_pixels) { + delete Plugin_128_pixels; + Plugin_128_pixels = nullptr; + } +} + +bool P128_data_struct::plugin_read(struct EventStruct *event) { + // there is no need to read them, just use current values + UserVar[event->BaseVarIndex] = mode; + UserVar[event->BaseVarIndex + 1] = savemode; + UserVar[event->BaseVarIndex + 2] = fadetime; + UserVar[event->BaseVarIndex + 3] = fadedelay; + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log = F("Lights: mode: "); + log += modeName[mode]; + log += F(" lastmode: "); + log += modeName[savemode]; + log += F(" fadetime: "); + log += (int)UserVar[event->BaseVarIndex + 2]; + log += F(" fadedelay: "); + log += (int)UserVar[event->BaseVarIndex + 3]; + addLog(LOG_LEVEL_INFO, log); + } + return true; +} + +bool P128_data_struct::plugin_write(struct EventStruct *event, + const String & string) { + bool success = false; + + String log = ""; + String command = parseString(string, 1); + + if ((command == F("neopixelfx")) || (command == F("nfx"))) { + success = true; + String subCommand = parseString(string, 2); + + if (subCommand == F("fadetime")) { + fadetime = parseString(string, 3).toInt(); + } + + else if (subCommand == F("fadedelay")) { + fadedelay = parseString(string, 3).toInt(); + } + + else if (subCommand == F("speed")) { + defaultspeed = parseString(string, 3).toInt(); + speed = defaultspeed; + } + + else if (subCommand == F("bgcolor")) { + hex2rrggbb(parseString(string, 3)); + } + + else if (subCommand == F("count")) { + count = parseString(string, 3).toInt(); + } + + else if ((subCommand == F("on")) || (subCommand == F("off"))) { + fadetime = 1000; + fadedelay = 0; + + fadetime = (parseString(string, 3) == "") + ? fadetime + : parseString(string, 3).toInt(); + fadedelay = (parseString(string, 4) == "") + ? fadedelay + : parseString(string, 4).toInt(); + + for (int pixel = 0; pixel < pixelCount; pixel++) { + r_pixel = (fadedelay < 0) + ? pixelCount - pixel - 1 + : pixel; + + starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); + + if ((subCommand == F("on")) && (mode == Off)) { // switch on + rgb_target[pixel] = rgb_old[pixel]; + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + } else if (subCommand == F("off")) { // switch off + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + rgb_target[pixel] = RgbColor(0); + } + } + + if ((subCommand == F("on")) && (mode == Off)) { // switch on + mode = (savemode == On) ? Fade : savemode; + } else if (subCommand == F("off")) { // switch off + savemode = mode; + mode = Fade; + } + + maxtime = starttime[r_pixel] + (fadetime / 20); + } + + else if (subCommand == F("dim")) { + Plugin_128_pixels->SetBrightness(parseString(string, 3).toInt()); + } + + else if (subCommand == F("line")) { + mode = On; + + hex2rgb(parseString(string, 5)); + + for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { + Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); + } + } + + else if (subCommand == F("tick")) { + mode = On; + + hex2rgb(parseString(string, 4)); + + // for (int i = 0; i < pixelCount ; i = i + (pixelCount / parseString(string, 3).toInt())) { + for (int i = 0; i < parseString(string, 3).toInt(); i++) { + Plugin_128_pixels->SetPixelColor(i * pixelCount / parseString(string, 3).toInt(), rgb); + } + } + + else if (subCommand == F("one")) { + mode = On; + + uint16_t pixnum = parseString(string, 3).toInt() - 1; + hex2rgb(parseString(string, 4)); + + Plugin_128_pixels->SetPixelColor(pixnum, rgb); + } + + else if ((subCommand == F("fade")) || (subCommand == F("all")) || (subCommand == F("rgb"))) { + mode = Fade; + + if ((subCommand == F("all")) || (subCommand == F("rgb"))) { + fadedelay = 0; + } + + hex2rgb(parseString(string, 3)); + hex2rgb_pixel(parseString(string, 3)); + + fadetime = (parseString(string, 4) == "") + ? fadetime + : parseString(string, 4).toInt(); + fadedelay = (parseString(string, 5) == "") + ? fadedelay + : parseString(string, 5).toInt(); + + for (int pixel = 0; pixel < pixelCount; pixel++) { + r_pixel = (fadedelay < 0) + ? pixelCount - pixel - 1 + : pixel; + + starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); + + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + } + maxtime = starttime[r_pixel] + (fadetime / 20); + } + + else if (subCommand == F("hsv")) { + mode = Fade; + fadedelay = 0; + rgb = + RgbColor(HsbColor(parseString(string, 3).toFloat() / 360, parseString(string, 4).toFloat() / 100, + parseString(string, 5).toFloat() / 100)); + + colorStr = ""; + rgb.R < 16 ? colorStr = "0" : ""; + colorStr += formatToHex(rgb.R, {}); + rgb.G < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.G, {}); + rgb.B < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.B, {}); + + hex2rgb_pixel(colorStr); + + fadetime = (parseString(string, 6) == "") + ? fadetime + : parseString(string, 6).toInt(); + fadedelay = (parseString(string, 7) == "") + ? fadedelay + : parseString(string, 7).toInt(); + + for (int pixel = 0; pixel < pixelCount; pixel++) { + r_pixel = (fadedelay < 0) + ? pixelCount - pixel - 1 + : pixel; + + starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); + + rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); + } + maxtime = starttime[r_pixel] + (fadetime / 20); + } + + else if (subCommand == F("hsvone")) { + mode = On; + rgb = + RgbColor(HsbColor(parseString(string, 4).toFloat() / 360, parseString(string, 5).toFloat() / 100, + parseString(string, 6).toFloat() / 100)); + + colorStr = ""; + rgb.R < 16 ? colorStr = "0" : ""; + colorStr += formatToHex(rgb.R, {}); + rgb.G < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.G, {}); + rgb.B < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.B, {}); + + hex2rgb(colorStr); + uint16_t pixnum = parseString(string, 3).toInt() - 1; + Plugin_128_pixels->SetPixelColor(pixnum, rgb); + } + + else if (subCommand == F("hsvline")) { + mode = On; + + rgb = + RgbColor(HsbColor(parseString(string, 5).toFloat() / 360, parseString(string, 6).toFloat() / 100, + parseString(string, 7).toFloat() / 100)); + + colorStr = ""; + rgb.R < 16 ? colorStr = "0" : ""; + colorStr += formatToHex(rgb.R, {}); + rgb.G < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.G, {}); + rgb.B < 16 ? colorStr += "0" : ""; + colorStr += formatToHex(rgb.B, {}); + + hex2rgb(colorStr); + + for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { + Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); + } + } + + else if (subCommand == F("rainbow")) { + fadeIn = (mode == Off) ? true : false; + mode = Rainbow; + starttimerb = counter20ms; + + rainbowspeed = (parseString(string, 3) == "") + ? speed + : parseString(string, 3).toInt(); + + fadetime = (parseString(string, 4) == "") + ? fadetime + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("colorfade")) { + mode = ColorFade; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + startpixel = (parseString(string, 5) == "") + ? 0 + : parseString(string, 5).toInt() - 1; + endpixel = (parseString(string, 6) == "") + ? pixelCount - 1 + : parseString(string, 6).toInt() - 1; + } + + else if (subCommand == F("kitt")) { + mode = Kitt; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + speed = (parseString(string, 4) == "") + ? defaultspeed + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("comet")) { + mode = Comet; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + speed = (parseString(string, 4) == "") + ? defaultspeed + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("theatre")) { + mode = Theatre; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + count = (parseString(string, 5) == "") + ? count + : parseString(string, 5).toInt(); + + speed = (parseString(string, 6) == "") + ? defaultspeed + : parseString(string, 6).toInt(); + + for (int i = 0; i < pixelCount; i++) { + if ((i / count) % 2 == 0) { + Plugin_128_pixels->SetPixelColor(i, rgb); + } else { + Plugin_128_pixels->SetPixelColor(i, rrggbb); + } + } + } + + else if (subCommand == F("scan")) { + mode = Scan; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("dualscan")) { + mode = Dualscan; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("twinkle")) { + mode = Twinkle; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("twinklefade")) { + mode = TwinkleFade; + + hex2rgb(parseString(string, 3)); + + count = (parseString(string, 4) == "") + ? count + : parseString(string, 4).toInt(); + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("sparkle")) { + mode = Sparkle; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + hex2rrggbb(parseString(string, 4)); + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("wipe")) { + mode = Wipe; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { + hex2rrggbb(parseString(string, 4)); + } else { + hex2rrggbb("000000"); + } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("dualwipe")) { + mode = Dualwipe; + + _counter_mode_step = 0; + + hex2rgb(parseString(string, 3)); + + if (parseString(string, 4) != "") { + hex2rrggbb(parseString(string, 4)); + } else { + hex2rrggbb("000000"); + } + + speed = (parseString(string, 5) == "") + ? defaultspeed + : parseString(string, 5).toInt(); + } + + else if (subCommand == F("faketv")) { + mode = FakeTV; + _counter_mode_step = 0; + + randomSeed(analogRead(A0)); + pixelNum = random(numPixels); // Begin at random point + + startpixel = (parseString(string, 3) == "") + ? 0 + : parseString(string, 3).toInt() - 1; + endpixel = (parseString(string, 4) == "") + ? pixelCount + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("fire")) { + mode = Fire; + + fps = (parseString(string, 3) == "") + ? fps + : parseString(string, 3).toInt(); + + fps = (fps == 0 || fps > 50) ? 50 : fps; + + brightness = (parseString(string, 4) == "") + ? brightness + : parseString(string, 4).toFloat(); + cooling = (parseString(string, 5) == "") + ? cooling + : parseString(string, 5).toFloat(); + sparking = (parseString(string, 6) == "") + ? sparking + : parseString(string, 6).toFloat(); + } + + else if (subCommand == F("fireflicker")) { + mode = FireFlicker; + + rev_intensity = (parseString(string, 3) == "") + ? rev_intensity + : parseString(string, 3).toInt(); + + speed = (parseString(string, 4) == "") + ? defaultspeed + : parseString(string, 4).toInt(); + } + + else if (subCommand == F("simpleclock")) { + mode = SimpleClock; + + # if defined(RGBW) || defined(GRBW) + + if (parseString(string, 3) != "") { + if (parseString(string, 3).length() <= 6) { + rgb_tick_s = + RgbwColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, + rgbStr2Num(parseString(string, 3))); + } else { + rgb_tick_s = + RgbwColor(rgbStr2Num(parseString(string, 3)) >> 24, + rgbStr2Num(parseString(string, 3)) >> 16, + rgbStr2Num(parseString(string, 3)) >> 8, + rgbStr2Num(parseString(string, 3))); + } + } + + if (parseString(string, 4) != "") { + if (parseString(string, 4).length() <= 6) { + rgb_tick_b = + RgbwColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, + rgbStr2Num(parseString(string, 4))); + } else { + rgb_tick_b = + RgbwColor(rgbStr2Num(parseString(string, 4)) >> 24, + rgbStr2Num(parseString(string, 4)) >> 16, + rgbStr2Num(parseString(string, 4)) >> 8, + rgbStr2Num(parseString(string, 4))); + } + } + + if (parseString(string, 5) != "") { + if (parseString(string, 5).length() <= 6) { + rgb_h = + RgbwColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, + rgbStr2Num(parseString(string, 5))); + } else { + rgb_h = + RgbwColor(rgbStr2Num(parseString(string, 5)) >> 24, + rgbStr2Num(parseString(string, 5)) >> 16, + rgbStr2Num(parseString(string, 5)) >> 8, + rgbStr2Num(parseString(string, 5))); + } + } + + if (parseString(string, 6) != "") { + if (parseString(string, 6).length() <= 6) { + rgb_m = + RgbwColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, + rgbStr2Num(parseString(string, 6))); + } else { + rgb_m = + RgbwColor(rgbStr2Num(parseString(string, 6)) >> 24, + rgbStr2Num(parseString(string, 6)) >> 16, + rgbStr2Num(parseString(string, 6)) >> 8, + rgbStr2Num(parseString(string, 6))); + } + } + + if (parseString(string, 7) != "") { + if (parseString(string, 7) == "off") { + rgb_s_off = true; + } else if (parseString(string, 7).length() <= 6) { + rgb_s_off = false; + rgb_s = + RgbwColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, + rgbStr2Num(parseString(string, 7))); + } else { + rgb_s_off = false; + rgb_s = + RgbwColor(rgbStr2Num(parseString(string, 7)) >> 24, + rgbStr2Num(parseString(string, 7)) >> 16, + rgbStr2Num(parseString(string, 7)) >> 8, + rgbStr2Num(parseString(string, 7))); + } + } + + if (parseString(string, 8) != "") { + hex2rrggbb(parseString(string, 8)); + } + + # else // if defined(RGBW) || defined(GRBW) + + rgb_tick_s = (parseString(string, 3) == "") + ? rgb_tick_s + : RgbColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, rgbStr2Num(parseString(string, 3))); + rgb_tick_b = (parseString(string, 4) == "") + ? rgb_tick_b + : RgbColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, rgbStr2Num(parseString(string, 4))); + rgb_h = (parseString(string, 5) == "") + ? rgb_h + : RgbColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, rgbStr2Num(parseString(string, 5))); + rgb_m = (parseString(string, 6) == "") + ? rgb_m + : RgbColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, rgbStr2Num(parseString(string, 6))); + + if (parseString(string, 7) != "") { + if (parseString(string, 7) == "off") { + rgb_s_off = true; + } else { + rgb_s_off = false; + rgb_s = + RgbColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, + rgbStr2Num(parseString(string, 7))); + } + } + + if (parseString(string, 8) != "") { hex2rrggbb(parseString(string, 8)); } + + # endif // if defined(RGBW) || defined(GRBW) + } + + else if (subCommand == F("stop")) { + mode = On; + } + + else if (subCommand == F("statusrequest")) {} + + else if ((subCommand != F("all")) && (subCommand != F("line")) + && (subCommand != F("one")) && (subCommand != F("fade")) + && (subCommand != F("dim")) && (subCommand != F("fadetime")) + && (subCommand != F("speed")) && (subCommand != F("fadedelay")) + && (subCommand != F("count")) && (subCommand != F("bgcolor")) + && (subCommand != F("on")) && (subCommand != F("off")) + && (subCommand != F("rgb")) && (subCommand != F("rainbow")) + && (subCommand != F("kitt")) && (subCommand != F("comet")) + && (subCommand != F("theatre")) && (subCommand != F("scan")) + && (subCommand != F("dualscan")) && (subCommand != F("twinkle")) + && (subCommand != F("sparkle")) && (subCommand != F("fire")) + && (subCommand != F("fireflicker")) && (subCommand != F("hsvone")) + && (subCommand != F("hsv")) && (subCommand != F("hsvline")) + && (subCommand != F("twinklefade")) && (subCommand != F("stop")) + && (subCommand != F("wipe")) && (subCommand != F("dualwipe")) + && (subCommand != F("colorfade")) && (subCommand != F("simpleclock")) + && (subCommand != F("faketv")) && (subCommand != F("statusrequest"))) { + log = F("NeoPixelBus: unknown subcommand: "); + log += subCommand; + addLog(LOG_LEVEL_INFO, log); + + String json; + printToWebJSON = true; + json += F("{\n"); + json += F("\"plugin\": \"128\",\n"); + json += F("\"log\": \""); + json += F("NeoPixelBus: unknown command: "); + json += subCommand; + json += F("\"\n"); + json += F("}\n"); + + // event->Source=EventValueSource::Enum::VALUE_SOURCE_HTTP; + SendStatus(event, json); // send http response to controller (JSON format) + printToWeb = false; + } + NeoPixelSendStatus(event); + } // command neopixel + + if (speed == 0) { mode = On; // speed = 0 = stop mode + } + speed = (speed > SPEED_MAX || speed < -SPEED_MAX) ? defaultspeed : speed; // avoid invalid values + fadetime = (fadetime <= 0) ? 20 : fadetime; + + return success; +} + +bool P128_data_struct::plugin_fifty_per_second(struct EventStruct *event) { + counter20ms++; + lastmode = mode; + + switch (mode) { + case Fade: + fade(); + break; + + case ColorFade: + colorfade(); + break; + + case Rainbow: + rainbow(); + break; + + case Kitt: + kitt(); + break; + + case Comet: + comet(); + break; + + case Theatre: + theatre(); + break; + + case Scan: + scan(); + break; + + case Dualscan: + dualscan(); + break; + + case Twinkle: + twinkle(); + break; + + case TwinkleFade: + twinklefade(); + break; + + case Sparkle: + sparkle(); + break; + + case Fire: + fire(); + break; + + case FireFlicker: + fire_flicker(); + break; + + case Wipe: + wipe(); + break; + + case Dualwipe: + dualwipe(); + break; + + case FakeTV: + faketv(); + break; + + case SimpleClock: + Plugin_128_simpleclock(); + break; + + default: + break; + } // switch mode + + Plugin_128_pixels->Show(); + + if (mode != lastmode) { + String log = ""; + log = F("NeoPixelBus: Mode Change: "); + log += modeName[mode]; + addLog(LOG_LEVEL_INFO, log); + NeoPixelSendStatus(event); + } + return true; +} + +void P128_data_struct::fade(void) { + for (int pixel = 0; pixel < pixelCount; pixel++) { + long zaehler = 20 * (counter20ms - starttime[pixel]); + float progress = (float)zaehler / (float)fadetime; + progress = (progress < 0) ? 0 : progress; + progress = (progress > 1) ? 1 : progress; + + # if defined(RGBW) || defined(GRBW) + RgbwColor updatedColor = RgbwColor::LinearBlend( + rgb_old[pixel], rgb_target[pixel], + progress); + # else // if defined(RGBW) || defined(GRBW) + RgbColor updatedColor = RgbColor::LinearBlend( + rgb_old[pixel], rgb_target[pixel], + progress); + # endif // if defined(RGBW) || defined(GRBW) + + if ((counter20ms > maxtime) && (Plugin_128_pixels->GetPixelColor(pixel).CalculateBrightness() == 0)) { + mode = Off; + } else if (counter20ms > maxtime) { + mode = On; + } + + Plugin_128_pixels->SetPixelColor(pixel, updatedColor); + } +} + +void P128_data_struct::colorfade(void) { + float progress = 0; + + difference = (endpixel - startpixel + pixelCount) % pixelCount; + + for (uint16_t i = 0; i <= difference; i++) + { + progress = (float)i / (difference - 1); + progress = (progress >= 1) ? 1 : progress; + progress = (progress <= 0) ? 0 : progress; + + # if defined(RGBW) || defined(GRBW) + RgbwColor updatedColor = RgbwColor::LinearBlend( + rgb, rrggbb, + progress); + # else // if defined(RGBW) || defined(GRBW) + RgbColor updatedColor = RgbColor::LinearBlend( + rgb, rrggbb, + progress); + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor((i + startpixel) % pixelCount, updatedColor); + } + mode = On; +} + +void P128_data_struct::wipe(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) { + if (speed > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step, rrggbb); + + if (_counter_mode_step > 0) { Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); } + } else { + Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step - 1, rrggbb); + + if (_counter_mode_step > 0) { Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step, rgb); } + } + + if (_counter_mode_step == pixelCount) { mode = On; } + _counter_mode_step++; + } +} + +void P128_data_struct::dualwipe(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) { + if (speed > 0) { + int i = _counter_mode_step - pixelCount; + i = abs(i); + Plugin_128_pixels->SetPixelColor(_counter_mode_step, rrggbb); + Plugin_128_pixels->SetPixelColor(i, rgb); + + if (_counter_mode_step > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); + Plugin_128_pixels->SetPixelColor(i - 1, rrggbb); + } + } else { + int i = (pixelCount / 2) - _counter_mode_step; + i = abs(i); + Plugin_128_pixels->SetPixelColor(_counter_mode_step + (pixelCount / 2), rrggbb); + Plugin_128_pixels->SetPixelColor(i, rgb); + + if (_counter_mode_step > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step + (pixelCount / 2) - 1, rgb); + Plugin_128_pixels->SetPixelColor(i - 1, rrggbb); + } + } + + if (_counter_mode_step >= pixelCount / 2) { + mode = On; + Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); + } + _counter_mode_step++; + } +} + +void P128_data_struct::faketv(void) { + if (counter20ms >= ftv_holdTime) { + difference = abs(endpixel - startpixel); + + if (ftv_elapsed >= ftv_fadeTime) { + // Read next 16-bit (5/6/5) color + ftv_hi = pgm_read_byte(&ftv_colors[pixelNum * 2]); + ftv_lo = pgm_read_byte(&ftv_colors[pixelNum * 2 + 1]); + + if (++pixelNum >= numPixels) { pixelNum = 0; } + + // Expand to 24-bit (8/8/8) + ftv_r8 = (ftv_hi & 0xF8) | (ftv_hi >> 5); + ftv_g8 = (ftv_hi << 5) | ((ftv_lo & 0xE0) >> 3) | ((ftv_hi & 0x06) >> 1); + ftv_b8 = (ftv_lo << 3) | ((ftv_lo & 0x1F) >> 2); + + // Apply gamma correction, further expand to 16/16/16 + ftv_nr = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_r8]) * 257; // New R/G/B + ftv_ng = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_g8]) * 257; + ftv_nb = (uint8_t)pgm_read_byte(&ftv_gamma8[ftv_b8]) * 257; + + ftv_totalTime = random(12, 125); // Semi-random pixel-to-pixel time + ftv_fadeTime = random(0, ftv_totalTime); // Pixel-to-pixel transition time + + if (random(10) < 3) { ftv_fadeTime = 0; // Force scene cut 30% of time + } + ftv_holdTime = counter20ms + ftv_totalTime - ftv_fadeTime; // Non-transition time + ftv_startTime = counter20ms; + } + + ftv_elapsed = counter20ms - ftv_startTime; + + if (ftv_fadeTime) { + ftv_r = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pr, ftv_nr); // 16-bit interp + ftv_g = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pg, ftv_ng); + ftv_b = map(ftv_elapsed, 0, ftv_fadeTime, ftv_pb, ftv_nb); + } else { // Avoid divide-by-ftv_fraczero in map() + ftv_r = ftv_nr; + ftv_g = ftv_ng; + ftv_b = ftv_nb; + } + + for (ftv_i = 0; ftv_i < difference; ftv_i++) { + ftv_r8 = ftv_r >> 8; // Quantize to 8-bit + ftv_g8 = ftv_g >> 8; + ftv_b8 = ftv_b >> 8; + ftv_frac = (ftv_i << 16) / difference; // LED index scaled to 0-65535 (16Bit) + + if ((ftv_r8 < 255) && ((ftv_r & 0xFF) >= ftv_frac)) { ftv_r8++; // Boost some fraction + } + + if ((ftv_g8 < 255) && ((ftv_g & 0xFF) >= ftv_frac)) { ftv_g8++; // of LEDs to handle + } + + if ((ftv_b8 < 255) && ((ftv_b & 0xFF) >= ftv_frac)) { ftv_b8++; // interp > 8bit + } + Plugin_128_pixels->SetPixelColor(ftv_i + startpixel, RgbColor(ftv_r8, ftv_g8, ftv_b8)); + } + + ftv_pr = ftv_nr; // Prev RGB = new RGB + ftv_pg = ftv_ng; + ftv_pb = ftv_nb; + } +} + +/* + * Cycles a rainbow over the entire string of LEDs. + */ +void P128_data_struct::rainbow(void) { + long zaehler = 20 * (counter20ms - starttimerb); + float progress = (float)zaehler / (float)fadetime; + + if (fadeIn == true) { + Plugin_128_pixels->SetBrightness(progress * 255); + fadeIn = (progress == 1) ? false : true; + } + + for (int i = 0; i < pixelCount; i++) + { + uint8_t r1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255) >> 16); + uint8_t g1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255) >> 8); + uint8_t b1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255)); + Plugin_128_pixels->SetPixelColor(i, RgbColor(r1, g1, b1)); + } + mode = (rainbowspeed == 0) ? On : Rainbow; +} + +/* + * Put a value 0 to 255 in to get a color value. + * The colours are a transition r -> g -> b -> back to r + * Inspired by the Adafruit examples. + */ +uint32_t P128_data_struct::Wheel(uint8_t pos) { + pos = 255 - pos; + + if (pos < 85) { + return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); + } else if (pos < 170) { + pos -= 85; + return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3); + } else { + pos -= 170; + return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0); + } +} + +// Larson Scanner K.I.T.T. +void P128_data_struct::kitt(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) + { + for (uint16_t i = 0; i < pixelCount; i++) { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(i, px_rgb); + } + + uint16_t pos = 0; + + if (_counter_mode_step < pixelCount) { + pos = _counter_mode_step; + } else { + pos = (pixelCount * 2) - _counter_mode_step - 2; + } + + Plugin_128_pixels->SetPixelColor(pos, rgb); + + _counter_mode_step = (_counter_mode_step + 1) % ((pixelCount * 2) - 2); + } +} + +// Firing comets from one end. +void P128_data_struct::comet(void) { + if (counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) + { + for (uint16_t i = 0; i < pixelCount; i++) { + if (speed > 0) { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(i); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(i, px_rgb); + } else { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(pixelCount - i - 1, px_rgb); + } + } + + if (speed > 0) { + Plugin_128_pixels->SetPixelColor(_counter_mode_step, rgb); + } else { + Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step - 1, rgb); + } + + _counter_mode_step = (_counter_mode_step + 1) % pixelCount; + } +} + +// Theatre lights +void P128_data_struct::theatre(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + if (speed > 0) { + Plugin_128_pixels->RotateLeft(1, 0, (pixelCount / count) * count - 1); + } else { + Plugin_128_pixels->RotateRight(1, 0, (pixelCount / count) * count - 1); + } + } +} + +/* + * Runs a single pixel back and forth. + */ +void P128_data_struct::scan(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + if (_counter_mode_step > uint16_t((pixelCount * 2) - 2)) { + _counter_mode_step = 0; + } + _counter_mode_step++; + + int i = _counter_mode_step - (pixelCount - 1); + i = abs(i); + + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + Plugin_128_pixels->SetPixelColor(abs(i), rgb); + } +} + +/* + * Runs two pixel back and forth in opposite directions. + */ +void P128_data_struct::dualscan(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) { + if (_counter_mode_step > uint16_t((pixelCount * 2) - 2)) { + _counter_mode_step = 0; + } + + _counter_mode_step++; + + int i = _counter_mode_step - (pixelCount - 1); + i = abs(i); + + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + Plugin_128_pixels->SetPixelColor(abs(i), rgb); + Plugin_128_pixels->SetPixelColor(pixelCount - (i + 1), rgb); + } +} + +/* + * Blink several LEDs on, reset, repeat. + * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ + */ +void P128_data_struct::twinkle(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + if (_counter_mode_step == 0) { + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + uint16_t min_leds = _max(1, pixelCount / 5); // make sure, at least one LED is on + uint16_t max_leds = _max(1, pixelCount / 2); // make sure, at least one LED is on + _counter_mode_step = random(min_leds, max_leds); + } + + Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); + + _counter_mode_step--; + } +} + +/* + * Blink several LEDs on, fading out. + */ +void P128_data_struct::twinklefade(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + for (uint16_t i = 0; i < pixelCount; i++) { + # if defined(RGBW) || defined(GRBW) + RgbwColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + px_rgb.W = px_rgb.W >> 1; + + # else // if defined(RGBW) || defined(GRBW) + + RgbColor px_rgb = Plugin_128_pixels->GetPixelColor(pixelCount - i - 1); + + // fade out (divide by 2) + px_rgb.R = px_rgb.R >> 1; + px_rgb.G = px_rgb.G >> 1; + px_rgb.B = px_rgb.B >> 1; + # endif // if defined(RGBW) || defined(GRBW) + + Plugin_128_pixels->SetPixelColor(i, px_rgb); + } + + if (random(count) < 50) { + Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); + } + } +} + +/* + * Blinks one LED at a time. + * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ + */ +void P128_data_struct::sparkle(void) { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + // Plugin_128_pixels->ClearTo(rrggbb); + for (int i = 0; i < pixelCount; i++) { Plugin_128_pixels->SetPixelColor(i, rrggbb); } + Plugin_128_pixels->SetPixelColor(random(pixelCount), rgb); + } +} + +void P128_data_struct::fire(void) { + if (counter20ms > fireTimer + 50 / fps) { + fireTimer = counter20ms; + Fire2012(); + RgbColor pixel; + + for (int i = 0; i < pixelCount; i++) { + pixel = leds[i]; + pixel = RgbColor::LinearBlend(pixel, RgbColor(0, 0, 0), (255 - brightness) / 255.0); + Plugin_128_pixels->SetPixelColor(i, pixel); + } + } +} + +/// Generate an 8-bit random number +uint8_t P128_data_struct::random8() { + rand16seed = (rand16seed * ((uint16_t)(2053))) + ((uint16_t)(13849)); + + // return the sum of the high and low bytes, for better + // mixing and non-sequential correlation + return (uint8_t)(((uint8_t)(rand16seed & 0xFF)) + + ((uint8_t)(rand16seed >> 8))); +} + +/// Generate an 8-bit random number between 0 and lim +/// @param lim the upper bound for the result +uint8_t P128_data_struct::random8(uint8_t lim) { + uint8_t r = random8(); + + r = (r * lim) >> 8; + return r; +} + +/// Generate an 8-bit random number in the given range +/// @param min the lower bound for the random number +/// @param lim the upper bound for the random number +uint8_t P128_data_struct::random8(uint8_t min, uint8_t lim) { + uint8_t delta = lim - min; + uint8_t r = random8(delta) + min; + + return r; +} + +/// subtract one byte from another, saturating at 0x00 +/// @returns i - j with a floor of 0 +uint8_t P128_data_struct::qsub8(uint8_t i, uint8_t j) { + int t = i - j; + + if (t < 0) { t = 0; } + return t; +} + +/// add one byte to another, saturating at 0xFF +/// @param i - first byte to add +/// @param j - second byte to add +/// @returns the sum of i & j, capped at 0xFF +uint8_t P128_data_struct::qadd8(uint8_t i, uint8_t j) { + unsigned int t = i + j; + + if (t > 255) { t = 255; } + return t; +} + +/// The "video" version of scale8 guarantees that the output will +/// be only be zero if one or both of the inputs are zero. If both +/// inputs are non-zero, the output is guaranteed to be non-zero. +/// This makes for better 'video'/LED dimming, at the cost of +/// several additional cycles. +uint8_t P128_data_struct::scale8_video(uint8_t i, uint8_t scale) { + uint8_t j = (((int)i * (int)scale) >> 8) + ((i && scale) ? 1 : 0); + + // uint8_t nonzeroscale = (scale != 0) ? 1 : 0; + // uint8_t j = (i == 0) ? 0 : (((int)i * (int)(scale) ) >> 8) + nonzeroscale; + return j; +} + +void P128_data_struct::Fire2012(void) { + // Array of temperature readings at each simulation cell + static byte heat[ARRAYSIZE]; + + // Step 1. Cool down every cell a little + for (int i = 0; i < pixelCount; i++) { + heat[i] = qsub8(heat[i], random8(0, ((cooling * 10) / pixelCount) + 2)); + } + + // Step 2. Heat from each cell drifts 'up' and diffuses a little + for (int k = pixelCount - 1; k >= 2; k--) { + heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; + } + + // Step 3. Randomly ignite new 'sparks' of heat near the bottom + if (random8() < sparking) { + int y = random8(7); + heat[y] = qadd8(heat[y], random8(160, 255)); + } + + // Step 4. Map from heat cells to LED colors + for (int j = 0; j < pixelCount; j++) { + RgbColor heatcolor; + + // Scale 'heat' down from 0-255 to 0-191, + // which can then be easily divided into three + // equal 'thirds' of 64 units each. + uint8_t t192 = scale8_video(heat[j], 191); + + // calculate a value that ramps up from + // zero to 255 in each 'third' of the scale. + uint8_t heatramp = t192 & 0x3F; // 0..63 + heatramp <<= 2; // scale up to 0..252 + + // now figure out which third of the spectrum we're in: + if (t192 & 0x80) { + // we're in the hottest third + heatcolor.R = 255; // full red + heatcolor.G = 255; // full green + heatcolor.B = heatramp; // ramp up blue + } else if (t192 & 0x40) { + // we're in the middle third + heatcolor.R = 255; // full red + heatcolor.G = heatramp; // ramp up green + heatcolor.B = 0; // no blue + } else { + // we're in the coolest third + heatcolor.R = heatramp; // ramp up red + heatcolor.G = 0; // no green + heatcolor.B = 0; // no blue + } + + int pixelnumber; + + if (gReverseDirection) { + pixelnumber = (pixelCount - 1) - j; + } else { + pixelnumber = j; + } + leds[pixelnumber] = heatcolor; + } +} + +/* + * Fire flicker function + */ +void P128_data_struct::fire_flicker() { + if ((counter20ms % (unsigned long)(SPEED_MAX / abs(speed)) == 0) && (speed != 0)) + { + byte w = 0; // (SEGMENT.colors[0] >> 24) & 0xFF; + byte r = 255; // (SEGMENT.colors[0] >> 16) & 0xFF; + byte g = 96; // (SEGMENT.colors[0] >> 8) & 0xFF; + byte b = 12; // (SEGMENT.colors[0] & 0xFF); + byte lum = max(w, max(r, max(g, b))) / rev_intensity; + + for (uint16_t i = 0; i <= numPixels - 1; i++) { + int flicker = random8(lum); + + # if defined(RGBW) || defined(GRBW) + Plugin_128_pixels->SetPixelColor(i, RgbwColor(max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0))); + # else // if defined(RGBW) || defined(GRBW) + Plugin_128_pixels->SetPixelColor(i, RgbColor(max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0))); + # endif // if defined(RGBW) || defined(GRBW) + } + } +} + +void P128_data_struct::Plugin_128_simpleclock() { + byte Hours = node_time.hour() % 12; + byte Minutes = node_time.minute(); + byte Seconds = node_time.second(); + byte big_tick = 15; + byte small_tick = 5; + + // hack for sub-second calculations.... reset when first time new second begins.. + if (cooling != Seconds) { maxtime = counter20ms; } + cooling = Seconds; + Plugin_128_pixels->ClearTo(rrggbb); + + for (int i = 0; i < (60 / small_tick); i++) { + if (i % (big_tick / small_tick) == 0) { Plugin_128_pixels->SetPixelColor((i * pixelCount * small_tick / 60) % pixelCount, rgb_tick_b); } + else { Plugin_128_pixels->SetPixelColor((i * pixelCount * small_tick / 60) % pixelCount, rgb_tick_s); } + } + + + for (int i = 0; i < pixelCount; i++) { + if (round((((float)Seconds + ((float)counter20ms - (float)maxtime) / 50.0) * (float)pixelCount) / 60.0) == i) { + if (rgb_s_off == false) { + Plugin_128_pixels->SetPixelColor(i, rgb_s); + } + } + else if (round((((float)Minutes * 60.0) + (float)Seconds) / 60.0 * (float)pixelCount / 60.0) == i) { + Plugin_128_pixels->SetPixelColor(i, rgb_m); + } + else if (round(((float)Hours + (float)Minutes / 60) * (float)pixelCount / 12.0) == i) { + Plugin_128_pixels->SetPixelColor(i, rgb_h); + Plugin_128_pixels->SetPixelColor((i + 1) % pixelCount, rgb_h); + Plugin_128_pixels->SetPixelColor((i - 1 + pixelCount) % pixelCount, rgb_h); + } + } +} + +uint32_t P128_data_struct::rgbStr2Num(String rgbStr) { + uint32_t rgbDec = (int)strtoul(&rgbStr[0], NULL, 16); + + return rgbDec; +} + +void P128_data_struct::hex2rgb(String hexcolor) { + colorStr = hexcolor; + # if defined(RGBW) || defined(GRBW) + hexcolor.length() <= 6 + ? rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) + : rgb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # else // if defined(RGBW) || defined(GRBW) + rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # endif // if defined(RGBW) || defined(GRBW) +} + +void P128_data_struct::hex2rrggbb(String hexcolor) { + backgroundcolorStr = hexcolor; + # if defined(RGBW) || defined(GRBW) + hexcolor.length() <= 6 + ? rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) + : rrggbb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # else // if defined(RGBW) || defined(GRBW) + rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # endif // if defined(RGBW) || defined(GRBW) +} + +void P128_data_struct::hex2rgb_pixel(String hexcolor) { + colorStr = hexcolor; + + for (int i = 0; i < pixelCount; i++) { + # if defined(RGBW) || defined(GRBW) + hexcolor.length() <= 6 + ? rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) + : rgb_target[i] = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # else // if defined(RGBW) || defined(GRBW) + rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + # endif // if defined(RGBW) || defined(GRBW) + } +} + +// --------------------------------------------------------------------------------- +// ------------------------------ JsonResponse ------------------------------------- +// --------------------------------------------------------------------------------- +void P128_data_struct::NeoPixelSendStatus(struct EventStruct *eventSource) { + String log = String(F("NeoPixelBusFX: Set ")) + rgb.R + + String(F("/")) + rgb.G + String(F("/")) + rgb.B; + + addLog(LOG_LEVEL_INFO, log); + + String json; + + printToWebJSON = true; + + json += F("{\n"); + json += F("\"plugin\": \"128"); + json += F("\",\n\"mode\": \""); + json += modeName[mode]; + json += F("\",\n\"lastmode\": \""); + json += modeName[savemode]; + json += F("\",\n\"fadetime\": \""); + json += fadetime; + json += F("\",\n\"fadedelay\": \""); + json += fadedelay; + json += F("\",\n\"dim\": \""); + json += Plugin_128_pixels->GetBrightness(); + json += F("\",\n\"rgb\": \""); + json += colorStr; + json += F("\",\n\"hue\": \""); + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).H * 360), 0); + json += F("\",\n\"saturation\": \""); + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).S * 100), 0); + json += F("\",\n\"brightness\": \""); + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).B * 100), 0); + json += F("\",\n\"bgcolor\": \""); + json += backgroundcolorStr; + json += F("\",\n\"count\": \""); + json += count; + json += F("\",\n\"speed\": \""); + json += speed; + json += F("\",\n\"pixelcount\": \""); + json += pixelCount; + json += F("\"\n}\n"); + SendStatus(eventSource, json); // send http response to controller (JSON format) + printToWeb = false; +} + #endif // ifdef USES_P128 diff --git a/src/src/PluginStructs/P128_data_struct.h b/src/src/PluginStructs/P128_data_struct.h index 6ceba495d..962206a07 100644 --- a/src/src/PluginStructs/P128_data_struct.h +++ b/src/src/PluginStructs/P128_data_struct.h @@ -2198,6 +2198,192 @@ const uint8_t PROGMEM ftv_gamma8[] = { 0X21, 0X86, 0X19, 0X04, 0X29, 0X66, 0X29, 0X45, 0X19, 0X25, 0X21, 0X25, 0X20, 0XE4, 0X21, 0XA6, 0X29, 0XE7, 0X32, 0X28 }; +# include +# include "../../ESPEasy-Globals.h" + +# define SPEED_MAX 50 +# define ARRAYSIZE 300 // Max LED Count + +// Choose your color order below: + +# define GRB // should be standard - SK6812(grb), WS2811, and WS2812 +// # define GRBW //This is used for SK6812rgbw pixels that have the separate white led in them. +// # define RGB //some older pixels +// # define RGBW //A four element color in the order of Red, Green, Blue, and then White. A common four element format. +// # define BRG //A three element color in the order of Blue, Red, and then Green. +// # define RBG //A three element color in the order of Red, Blue, and then Green. + +# define NEOPIXEL_LIB NeoPixelBrightnessBus // Neopixel library type +# if defined(ESP32) +# define METHOD NeoEsp32Rmt1800KbpsMethod // RMT, user selected pin - use NeoEsp32RmtMethod (should also work on ESP32S2) +# endif // if defined(ESP32) +# if defined(ESP8266) +# define METHOD NeoEsp8266Uart1800KbpsMethod // GPIO2 - use NeoEsp8266Uart0800KbpsMethod for GPIO1(TX) +# endif // if defined(ESP32) + +# if defined GRB + # define FEATURE NeoGrbFeature +# elif defined GRBW + # define FEATURE NeoGrbwFeature +# elif defined RGB + # define FEATURE NeoRgbFeature +# elif defined RGBW + # define FEATURE NeoRgbwFeature +# elif defined BRG + # define FEATURE NeoBrgFeature +# elif defined RBG + # define FEATURE NeoRbgFeature +# else // if defined GRB + # define FEATURE NeoGrbFeature +# endif // if defined GRB + +# define numPixels (sizeof(ftv_colors) / sizeof(ftv_colors[0])) + +const float pi = 3.1415926535897932384626433832795; + +enum P128_modetype { + Off, On, Fade, ColorFade, Rainbow, Kitt, Comet, + Theatre, Scan, Dualscan, Twinkle, TwinkleFade, Sparkle, Fire, + FireFlicker, Wipe, Dualwipe, FakeTV, SimpleClock +}; + +struct P128_data_struct : public PluginTaskData_base { +public: + + P128_data_struct(int8_t _gpioPin, + uint16_t _pixelCount); + + P128_data_struct() = delete; + ~P128_data_struct(); + + bool plugin_fifty_per_second(struct EventStruct *event); + bool plugin_read(struct EventStruct *event); + bool plugin_write(struct EventStruct *event, + const String & string); + +private: + + NEOPIXEL_LIB *Plugin_128_pixels = nullptr; + + int8_t gpioPin; + + uint16_t pos, + color, + r_pixel, + startpixel, + endpixel, + difference, + fps = 50, + colorcount; + +# if defined(RGBW) || defined(GRBW) + RgbwColor rgb_target[ARRAYSIZE], + rgb_old[ARRAYSIZE], + rgb, rrggbb, + rgb_tick_b = HtmlColor(0x505050), + rgb_tick_s = HtmlColor(0x101010), + rgb_m = HtmlColor(0x00FF00), + rgb_h = HtmlColor(0x0000FF), + rgb_s = HtmlColor(0xFF0000); +# else // if defined(RGBW) || defined(GRBW) + RgbColor rgb_target[ARRAYSIZE], + rgb_old[ARRAYSIZE], + rgb, rrggbb, + rgb_tick_b = HtmlColor(0x505050), + rgb_tick_s = HtmlColor(0x101010), + rgb_m = HtmlColor(0x00FF00), + rgb_h = HtmlColor(0x0000FF), + rgb_s = HtmlColor(0xFF0000); +# endif // if defined(RGBW) || defined(GRBW) + + int16_t fadedelay = 20; + + uint16_t pixelCount = ARRAYSIZE; + + int8_t defaultspeed = 25, + rainbowspeed = 1, + speed = 25, + count = 1, + rev_intensity = 3; + + uint32_t _counter_mode_step = 0, + fadetime = 1000, + ftv_holdTime, + pixelNum; + + uint16_t ftv_pr = 0, ftv_pg = 0, ftv_pb = 0; // Prev R, G, B; + uint32_t ftv_totalTime, ftv_fadeTime, ftv_startTime, ftv_elapsed; + uint16_t ftv_nr, ftv_ng, ftv_nb, ftv_r, ftv_g, ftv_b, ftv_i, ftv_frac; + uint8_t ftv_hi, ftv_lo, ftv_r8, ftv_g8, ftv_b8; + + String colorStr, + backgroundcolorStr; + + bool gReverseDirection = false; + bool rgb_s_off = false; + bool fadeIn = false; + + byte cooling = 50, + sparking = 120, + brightness = 31; + + unsigned long counter20ms = 0, + starttime[ARRAYSIZE], + starttimerb, + maxtime = 0; + + P128_modetype mode = P128_modetype::Off, + savemode = P128_modetype::Off, + lastmode = P128_modetype::Off; + + void fade(void); + void colorfade(void); + void wipe(void); + void dualwipe(void); + void faketv(void); + void rainbow(void); + uint32_t Wheel(uint8_t pos); + void kitt(void); + void comet(void); + void theatre(void); + void scan(void); + void dualscan(void); + void twinkle(void); + void twinklefade(void); + void sparkle(void); + + // Fire + unsigned long fireTimer; + RgbColor leds[ARRAYSIZE]; + void fire(void); + + /// random number seed + uint16_t rand16seed; // = RAND16_SEED; + uint8_t random8(); + uint8_t random8(uint8_t lim); + uint8_t random8(uint8_t min, + uint8_t lim); + uint8_t qsub8(uint8_t i, + uint8_t j); + uint8_t qadd8(uint8_t i, + uint8_t j); + uint8_t scale8_video(uint8_t i, + uint8_t scale); + void Fire2012(void); + void fire_flicker(); + void Plugin_128_simpleclock(); + uint32_t rgbStr2Num(String rgbStr); + void hex2rgb(String hexcolor); + void hex2rrggbb(String hexcolor); + void hex2rgb_pixel(String hexcolor); + void NeoPixelSendStatus(struct EventStruct *eventSource); + + const char *modeName[19] = { + "off", "on", "fade", "colorfade", "rainbow", "kitt", "comet", + "theatre", "scan", "dualscan", "twinkle", "twinklefade", "sparkle", "fire", + "fireflicker", "wipe", "dualwipe", "faketv", "simpleclock" + }; +}; #endif // ifdef USES_P128 #endif // ifndef PLUGINSTRUCTS_P128_DATA_STRUCT_H From 91bca53a5347f5b1c54a2b327d0d54bf9377cd09 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Wed, 5 Jan 2022 21:30:42 +0100 Subject: [PATCH 004/161] [P128] Initialization improvements, code optimizations --- src/_P128_NeoPixelBusFX.ino | 13 +- src/src/PluginStructs/P128_data_struct.cpp | 618 +++++++++++---------- src/src/PluginStructs/P128_data_struct.h | 54 +- 3 files changed, 363 insertions(+), 322 deletions(-) diff --git a/src/_P128_NeoPixelBusFX.ino b/src/_P128_NeoPixelBusFX.ino index f7f0f746d..e4a83c170 100644 --- a/src/_P128_NeoPixelBusFX.ino +++ b/src/_P128_NeoPixelBusFX.ino @@ -7,6 +7,9 @@ // ####################################################################################################### // Changelog: +// 2022-01-04, tonhuisman Code optimizations, reduce calls to parseString and rgbStr2Num, string handling +// Ensure no instance is still running when PLUGIN_INIT is called, as it will cause RMT issues +// 2022-01-03, tonhuisman Code optimizations, struct variable initialization // 2022-01-02, tonhuisman Move all code to Plugin_data_struct, with minor modifications (initialization, *char[] size) // 2022-01-02, tonhuisman Fixed ESP32 related issues (conditional compilation, wrong stripe type) // Add configuration for ESP32 GPIO pin @@ -202,8 +205,14 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { - initPluginTaskData(event->TaskIndex, - new (std::nothrow) P128_data_struct(PIN(0), PCONFIG(0))); + // *Ensure* there is no currently running process, if so, just clear it out neatly + P128_data_struct *P128_clear = static_cast(getPluginTaskData(event->TaskIndex)); + + if (nullptr != P128_clear) { + clearPluginTaskData(event->TaskIndex); + } + + initPluginTaskData(event->TaskIndex, new (std::nothrow) P128_data_struct(PIN(0), PCONFIG(0))); P128_data_struct *P128_data = static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr == P128_data) { diff --git a/src/src/PluginStructs/P128_data_struct.cpp b/src/src/PluginStructs/P128_data_struct.cpp index e7a89fc45..aa91b83fc 100644 --- a/src/src/PluginStructs/P128_data_struct.cpp +++ b/src/src/PluginStructs/P128_data_struct.cpp @@ -3,11 +3,9 @@ # include "../PluginStructs/P128_data_struct.h" -// TODO: implementation code - -//***************************************************************/ -// -//***************************************************************/ +// ***************************************************************/ +// Constructor +// ***************************************************************/ P128_data_struct::P128_data_struct(int8_t _gpioPin, uint16_t _pixelCount) : gpioPin(_gpioPin), pixelCount(_pixelCount) { @@ -25,9 +23,9 @@ P128_data_struct::P128_data_struct(int8_t _gpioPin, // pixelCount = _pixelCount; } -//***************************************************************/ +// ***************************************************************/ // Destructor -//***************************************************************/ +// ***************************************************************/ P128_data_struct::~P128_data_struct() { if (Plugin_128_pixels) { delete Plugin_128_pixels; @@ -35,19 +33,19 @@ P128_data_struct::~P128_data_struct() { } } -bool P128_data_struct::plugin_read(struct EventStruct *event) { +bool P128_data_struct::plugin_read(struct EventStruct *event) { // there is no need to read them, just use current values - UserVar[event->BaseVarIndex] = mode; - UserVar[event->BaseVarIndex + 1] = savemode; + UserVar[event->BaseVarIndex] = static_cast(mode); + UserVar[event->BaseVarIndex + 1] = static_cast(savemode); UserVar[event->BaseVarIndex + 2] = fadetime; UserVar[event->BaseVarIndex + 3] = fadedelay; if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log = F("Lights: mode: "); - log += modeName[mode]; + log += P128_modeType_toString(mode); log += F(" lastmode: "); - log += modeName[savemode]; + log += P128_modeType_toString(savemode); log += F(" fadetime: "); log += (int)UserVar[event->BaseVarIndex + 2]; log += F(" fadedelay: "); @@ -61,44 +59,55 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, const String & string) { bool success = false; - String log = ""; + String log; String command = parseString(string, 1); if ((command == F("neopixelfx")) || (command == F("nfx"))) { success = true; String subCommand = parseString(string, 2); + String str3 = parseString(string, 3); + int32_t str3i = str3.toInt(); + String str4 = parseString(string, 4); + int32_t str4i = str4.toInt(); + String str5 = parseString(string, 5); + int32_t str5i = str5.toInt(); + String str6 = parseString(string, 6); + int32_t str6i = str6.toInt(); + String str7 = parseString(string, 7); + int32_t str7i = str7.toInt(); + if (subCommand == F("fadetime")) { - fadetime = parseString(string, 3).toInt(); + fadetime = str3i; } else if (subCommand == F("fadedelay")) { - fadedelay = parseString(string, 3).toInt(); + fadedelay = str3i; } else if (subCommand == F("speed")) { - defaultspeed = parseString(string, 3).toInt(); + defaultspeed = str3i; speed = defaultspeed; } else if (subCommand == F("bgcolor")) { - hex2rrggbb(parseString(string, 3)); + hex2rrggbb(str3); } else if (subCommand == F("count")) { - count = parseString(string, 3).toInt(); + count = str3i; } else if ((subCommand == F("on")) || (subCommand == F("off"))) { fadetime = 1000; fadedelay = 0; - fadetime = (parseString(string, 3) == "") + fadetime = str3.isEmpty() ? fadetime - : parseString(string, 3).toInt(); - fadedelay = (parseString(string, 4) == "") + : str3i; + fadedelay = str4.isEmpty() ? fadedelay - : parseString(string, 4).toInt(); + : str4i; for (int pixel = 0; pixel < pixelCount; pixel++) { r_pixel = (fadedelay < 0) @@ -107,75 +116,75 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, starttime[r_pixel] = counter20ms + (pixel * abs(fadedelay) / 20); - if ((subCommand == F("on")) && (mode == Off)) { // switch on + if ((subCommand == F("on")) && (mode == P128_modetype::Off)) { // switch on rgb_target[pixel] = rgb_old[pixel]; rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); - } else if (subCommand == F("off")) { // switch off + } else if (subCommand == F("off")) { // switch off rgb_old[pixel] = Plugin_128_pixels->GetPixelColor(pixel); rgb_target[pixel] = RgbColor(0); } } - if ((subCommand == F("on")) && (mode == Off)) { // switch on - mode = (savemode == On) ? Fade : savemode; - } else if (subCommand == F("off")) { // switch off + if ((subCommand == F("on")) && (mode == P128_modetype::Off)) { // switch on + mode = (savemode == P128_modetype::On) ? P128_modetype::Fade : savemode; + } else if (subCommand == F("off")) { // switch off savemode = mode; - mode = Fade; + mode = P128_modetype::Fade; } maxtime = starttime[r_pixel] + (fadetime / 20); } else if (subCommand == F("dim")) { - Plugin_128_pixels->SetBrightness(parseString(string, 3).toInt()); + Plugin_128_pixels->SetBrightness(str3i); } else if (subCommand == F("line")) { - mode = On; + mode = P128_modetype::On; - hex2rgb(parseString(string, 5)); + hex2rgb(str5); - for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { - Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); + for (int i = 0; i <= (str4i - str3i + pixelCount) % pixelCount; i++) { + Plugin_128_pixels->SetPixelColor((i + str3i - 1) % pixelCount, rgb); } } else if (subCommand == F("tick")) { - mode = On; + mode = P128_modetype::On; - hex2rgb(parseString(string, 4)); + hex2rgb(str4); // for (int i = 0; i < pixelCount ; i = i + (pixelCount / parseString(string, 3).toInt())) { - for (int i = 0; i < parseString(string, 3).toInt(); i++) { - Plugin_128_pixels->SetPixelColor(i * pixelCount / parseString(string, 3).toInt(), rgb); + for (int i = 0; i < str3i; i++) { + Plugin_128_pixels->SetPixelColor(i * pixelCount / str3i, rgb); } } else if (subCommand == F("one")) { - mode = On; + mode = P128_modetype::On; - uint16_t pixnum = parseString(string, 3).toInt() - 1; - hex2rgb(parseString(string, 4)); + uint16_t pixnum = str3i - 1; + hex2rgb(str4); Plugin_128_pixels->SetPixelColor(pixnum, rgb); } else if ((subCommand == F("fade")) || (subCommand == F("all")) || (subCommand == F("rgb"))) { - mode = Fade; + mode = P128_modetype::Fade; if ((subCommand == F("all")) || (subCommand == F("rgb"))) { fadedelay = 0; } - hex2rgb(parseString(string, 3)); - hex2rgb_pixel(parseString(string, 3)); + hex2rgb(str3); + hex2rgb_pixel(str3); - fadetime = (parseString(string, 4) == "") + fadetime = str4.isEmpty() ? fadetime - : parseString(string, 4).toInt(); - fadedelay = (parseString(string, 5) == "") + : str4i; + fadedelay = str5.isEmpty() ? fadedelay - : parseString(string, 5).toInt(); + : str5i; for (int pixel = 0; pixel < pixelCount; pixel++) { r_pixel = (fadedelay < 0) @@ -190,28 +199,22 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, } else if (subCommand == F("hsv")) { - mode = Fade; + mode = P128_modetype::Fade; fadedelay = 0; rgb = - RgbColor(HsbColor(parseString(string, 3).toFloat() / 360, parseString(string, 4).toFloat() / 100, - parseString(string, 5).toFloat() / 100)); + RgbColor(HsbColor(str3.toFloat() / 360, str4.toFloat() / 100, + str5.toFloat() / 100)); - colorStr = ""; - rgb.R < 16 ? colorStr = "0" : ""; - colorStr += formatToHex(rgb.R, {}); - rgb.G < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.G, {}); - rgb.B < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.B, {}); + rgb2colorStr(); hex2rgb_pixel(colorStr); - fadetime = (parseString(string, 6) == "") + fadetime = str6.isEmpty() ? fadetime - : parseString(string, 6).toInt(); - fadedelay = (parseString(string, 7) == "") + : str6i; + fadedelay = str7.isEmpty() ? fadedelay - : parseString(string, 7).toInt(); + : str7i; for (int pixel = 0; pixel < pixelCount; pixel++) { r_pixel = (fadedelay < 0) @@ -226,113 +229,101 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, } else if (subCommand == F("hsvone")) { - mode = On; + mode = P128_modetype::On; rgb = - RgbColor(HsbColor(parseString(string, 4).toFloat() / 360, parseString(string, 5).toFloat() / 100, - parseString(string, 6).toFloat() / 100)); + RgbColor(HsbColor(str4.toFloat() / 360, str5.toFloat() / 100, + str6.toFloat() / 100)); - colorStr = ""; - rgb.R < 16 ? colorStr = "0" : ""; - colorStr += formatToHex(rgb.R, {}); - rgb.G < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.G, {}); - rgb.B < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.B, {}); + rgb2colorStr(); hex2rgb(colorStr); - uint16_t pixnum = parseString(string, 3).toInt() - 1; + uint16_t pixnum = str3i - 1; Plugin_128_pixels->SetPixelColor(pixnum, rgb); } else if (subCommand == F("hsvline")) { - mode = On; + mode = P128_modetype::On; rgb = - RgbColor(HsbColor(parseString(string, 5).toFloat() / 360, parseString(string, 6).toFloat() / 100, - parseString(string, 7).toFloat() / 100)); + RgbColor(HsbColor(str5.toFloat() / 360, str6.toFloat() / 100, + str7.toFloat() / 100)); - colorStr = ""; - rgb.R < 16 ? colorStr = "0" : ""; - colorStr += formatToHex(rgb.R, {}); - rgb.G < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.G, {}); - rgb.B < 16 ? colorStr += "0" : ""; - colorStr += formatToHex(rgb.B, {}); + rgb2colorStr(); hex2rgb(colorStr); - for (int i = 0; i <= (parseString(string, 4).toInt() - parseString(string, 3).toInt() + pixelCount) % pixelCount; i++) { - Plugin_128_pixels->SetPixelColor((i + parseString(string, 3).toInt() - 1) % pixelCount, rgb); + for (int i = 0; i <= (str4i - str3i + pixelCount) % pixelCount; i++) { + Plugin_128_pixels->SetPixelColor((i + str3i - 1) % pixelCount, rgb); } } else if (subCommand == F("rainbow")) { - fadeIn = (mode == Off) ? true : false; - mode = Rainbow; + fadeIn = (mode == P128_modetype::Off) ? true : false; + mode = P128_modetype::Rainbow; starttimerb = counter20ms; - rainbowspeed = (parseString(string, 3) == "") + rainbowspeed = str3.isEmpty() ? speed - : parseString(string, 3).toInt(); + : str3i; - fadetime = (parseString(string, 4) == "") + fadetime = str4.isEmpty() ? fadetime - : parseString(string, 4).toInt(); + : str4i; } else if (subCommand == F("colorfade")) { - mode = ColorFade; + mode = P128_modetype::ColorFade; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + if (!str4.isEmpty()) { hex2rrggbb(str4); } - startpixel = (parseString(string, 5) == "") + startpixel = str5.isEmpty() ? 0 - : parseString(string, 5).toInt() - 1; - endpixel = (parseString(string, 6) == "") + : str5i - 1; + endpixel = str6.isEmpty() ? pixelCount - 1 - : parseString(string, 6).toInt() - 1; + : str6i - 1; } else if (subCommand == F("kitt")) { - mode = Kitt; + mode = P128_modetype::Kitt; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - speed = (parseString(string, 4) == "") + speed = str4.isEmpty() ? defaultspeed - : parseString(string, 4).toInt(); + : str4i; } else if (subCommand == F("comet")) { - mode = Comet; + mode = P128_modetype::Comet; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - speed = (parseString(string, 4) == "") + speed = str4.isEmpty() ? defaultspeed - : parseString(string, 4).toInt(); + : str4i; } else if (subCommand == F("theatre")) { - mode = Theatre; + mode = P128_modetype::Theatre; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + if (!str4.isEmpty()) { hex2rrggbb(str4); } - count = (parseString(string, 5) == "") + count = str5.isEmpty() ? count - : parseString(string, 5).toInt(); + : str5i; - speed = (parseString(string, 6) == "") + speed = str6.isEmpty() ? defaultspeed - : parseString(string, 6).toInt(); + : str6i; for (int i = 0; i < pixelCount; i++) { if ((i / count) % 2 == 0) { @@ -344,233 +335,233 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, } else if (subCommand == F("scan")) { - mode = Scan; + mode = P128_modetype::Scan; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + if (!str4.isEmpty()) { hex2rrggbb(str4); } - speed = (parseString(string, 5) == "") + speed = str5.isEmpty() ? defaultspeed - : parseString(string, 5).toInt(); + : str5i; } else if (subCommand == F("dualscan")) { - mode = Dualscan; + mode = P128_modetype::Dualscan; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + if (!str4.isEmpty()) { hex2rrggbb(str4); } - speed = (parseString(string, 5) == "") + speed = str5.isEmpty() ? defaultspeed - : parseString(string, 5).toInt(); + : str5i; } else if (subCommand == F("twinkle")) { - mode = Twinkle; + mode = P128_modetype::Twinkle; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - if (parseString(string, 4) != "") { hex2rrggbb(parseString(string, 4)); } + if (!str4.isEmpty()) { hex2rrggbb(str4); } - speed = (parseString(string, 5) == "") + speed = str5.isEmpty() ? defaultspeed - : parseString(string, 5).toInt(); + : str5i; } else if (subCommand == F("twinklefade")) { - mode = TwinkleFade; + mode = P128_modetype::TwinkleFade; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - count = (parseString(string, 4) == "") + count = str4.isEmpty() ? count - : parseString(string, 4).toInt(); + : str4i; - speed = (parseString(string, 5) == "") + speed = str5.isEmpty() ? defaultspeed - : parseString(string, 5).toInt(); + : str5i; } else if (subCommand == F("sparkle")) { - mode = Sparkle; + mode = P128_modetype::Sparkle; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); - hex2rrggbb(parseString(string, 4)); + hex2rgb(str3); + hex2rrggbb(str4); - speed = (parseString(string, 5) == "") + speed = str5.isEmpty() ? defaultspeed - : parseString(string, 5).toInt(); + : str5i; } else if (subCommand == F("wipe")) { - mode = Wipe; + mode = P128_modetype::Wipe; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - if (parseString(string, 4) != "") { - hex2rrggbb(parseString(string, 4)); + if (!str4.isEmpty()) { + hex2rrggbb(str4); } else { hex2rrggbb("000000"); } - speed = (parseString(string, 5) == "") + speed = str5.isEmpty() ? defaultspeed - : parseString(string, 5).toInt(); + : str5i; } else if (subCommand == F("dualwipe")) { - mode = Dualwipe; + mode = P128_modetype::Dualwipe; _counter_mode_step = 0; - hex2rgb(parseString(string, 3)); + hex2rgb(str3); - if (parseString(string, 4) != "") { - hex2rrggbb(parseString(string, 4)); + if (!str4.isEmpty()) { + hex2rrggbb(str4); } else { hex2rrggbb("000000"); } - speed = (parseString(string, 5) == "") + speed = str5.isEmpty() ? defaultspeed - : parseString(string, 5).toInt(); + : str5i; } else if (subCommand == F("faketv")) { - mode = FakeTV; + mode = P128_modetype::FakeTV; _counter_mode_step = 0; randomSeed(analogRead(A0)); pixelNum = random(numPixels); // Begin at random point - startpixel = (parseString(string, 3) == "") + startpixel = str3.isEmpty() ? 0 - : parseString(string, 3).toInt() - 1; - endpixel = (parseString(string, 4) == "") + : str3i - 1; + endpixel = str4.isEmpty() ? pixelCount - : parseString(string, 4).toInt(); + : str4i; } else if (subCommand == F("fire")) { - mode = Fire; + mode = P128_modetype::Fire; - fps = (parseString(string, 3) == "") + fps = str3.isEmpty() ? fps - : parseString(string, 3).toInt(); + : str3i; fps = (fps == 0 || fps > 50) ? 50 : fps; - brightness = (parseString(string, 4) == "") + brightness = str4.isEmpty() ? brightness - : parseString(string, 4).toFloat(); - cooling = (parseString(string, 5) == "") + : str4.toFloat(); + cooling = str5.isEmpty() ? cooling - : parseString(string, 5).toFloat(); - sparking = (parseString(string, 6) == "") + : str5.toFloat(); + sparking = str6.isEmpty() ? sparking - : parseString(string, 6).toFloat(); + : str6.toFloat(); } else if (subCommand == F("fireflicker")) { - mode = FireFlicker; + mode = P128_modetype::FireFlicker; - rev_intensity = (parseString(string, 3) == "") + rev_intensity = str3.isEmpty() ? rev_intensity - : parseString(string, 3).toInt(); + : str3i; - speed = (parseString(string, 4) == "") + speed = str4.isEmpty() ? defaultspeed - : parseString(string, 4).toInt(); + : str4i; } else if (subCommand == F("simpleclock")) { - mode = SimpleClock; + mode = P128_modetype::SimpleClock; - # if defined(RGBW) || defined(GRBW) + # if defined(RGBW) || defined(GRBW) - if (parseString(string, 3) != "") { - if (parseString(string, 3).length() <= 6) { + if (!str3.isEmpty()) { + if (str3.length() <= 6) { rgb_tick_s = - RgbwColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, - rgbStr2Num(parseString(string, 3))); + RgbwColor(rgbStr2Num(str3) >> 16, rgbStr2Num(str3) >> 8, + rgbStr2Num(str3)); } else { rgb_tick_s = - RgbwColor(rgbStr2Num(parseString(string, 3)) >> 24, - rgbStr2Num(parseString(string, 3)) >> 16, - rgbStr2Num(parseString(string, 3)) >> 8, - rgbStr2Num(parseString(string, 3))); + RgbwColor(rgbStr2Num(str3) >> 24, + rgbStr2Num(str3) >> 16, + rgbStr2Num(str3) >> 8, + rgbStr2Num(str3)); } } - if (parseString(string, 4) != "") { - if (parseString(string, 4).length() <= 6) { + if (!str4.isEmpty()) { + if (str4.length() <= 6) { rgb_tick_b = - RgbwColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, - rgbStr2Num(parseString(string, 4))); + RgbwColor(rgbStr2Num(str4) >> 16, rgbStr2Num(str4) >> 8, + rgbStr2Num(str4)); } else { rgb_tick_b = - RgbwColor(rgbStr2Num(parseString(string, 4)) >> 24, - rgbStr2Num(parseString(string, 4)) >> 16, - rgbStr2Num(parseString(string, 4)) >> 8, - rgbStr2Num(parseString(string, 4))); + RgbwColor(rgbStr2Num(str4) >> 24, + rgbStr2Num(str4) >> 16, + rgbStr2Num(str4) >> 8, + rgbStr2Num(str4)); } } - if (parseString(string, 5) != "") { - if (parseString(string, 5).length() <= 6) { + if (!str5.isEmpty()) { + if (str5.length() <= 6) { rgb_h = - RgbwColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, - rgbStr2Num(parseString(string, 5))); + RgbwColor(rgbStr2Num(str5) >> 16, rgbStr2Num(str5) >> 8, + rgbStr2Num(str5)); } else { rgb_h = - RgbwColor(rgbStr2Num(parseString(string, 5)) >> 24, - rgbStr2Num(parseString(string, 5)) >> 16, - rgbStr2Num(parseString(string, 5)) >> 8, - rgbStr2Num(parseString(string, 5))); + RgbwColor(rgbStr2Num(str5) >> 24, + rgbStr2Num(str5) >> 16, + rgbStr2Num(str5) >> 8, + rgbStr2Num(str5)); } } - if (parseString(string, 6) != "") { - if (parseString(string, 6).length() <= 6) { + if (!str6.isEmpty()) { + if (str6.length() <= 6) { rgb_m = - RgbwColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, - rgbStr2Num(parseString(string, 6))); + RgbwColor(rgbStr2Num(str6) >> 16, rgbStr2Num(str6) >> 8, + rgbStr2Num(str6)); } else { rgb_m = - RgbwColor(rgbStr2Num(parseString(string, 6)) >> 24, - rgbStr2Num(parseString(string, 6)) >> 16, - rgbStr2Num(parseString(string, 6)) >> 8, - rgbStr2Num(parseString(string, 6))); + RgbwColor(rgbStr2Num(str6) >> 24, + rgbStr2Num(str6) >> 16, + rgbStr2Num(str6) >> 8, + rgbStr2Num(str6)); } } - if (parseString(string, 7) != "") { - if (parseString(string, 7) == "off") { + if (!str7.isEmpty()) { + if (str7 == F("off")) { rgb_s_off = true; - } else if (parseString(string, 7).length() <= 6) { + } else if (str7.length() <= 6) { rgb_s_off = false; rgb_s = - RgbwColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, - rgbStr2Num(parseString(string, 7))); + RgbwColor(rgbStr2Num(str7) >> 16, rgbStr2Num(str7) >> 8, + rgbStr2Num(str7)); } else { rgb_s_off = false; rgb_s = - RgbwColor(rgbStr2Num(parseString(string, 7)) >> 24, - rgbStr2Num(parseString(string, 7)) >> 16, - rgbStr2Num(parseString(string, 7)) >> 8, - rgbStr2Num(parseString(string, 7))); + RgbwColor(rgbStr2Num(str7) >> 24, + rgbStr2Num(str7) >> 16, + rgbStr2Num(str7) >> 8, + rgbStr2Num(str7)); } } @@ -578,39 +569,39 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, hex2rrggbb(parseString(string, 8)); } - # else // if defined(RGBW) || defined(GRBW) + # else // if defined(RGBW) || defined(GRBW) - rgb_tick_s = (parseString(string, 3) == "") + rgb_tick_s = str3.isEmpty() ? rgb_tick_s - : RgbColor(rgbStr2Num(parseString(string, 3)) >> 16, rgbStr2Num(parseString(string, 3)) >> 8, rgbStr2Num(parseString(string, 3))); - rgb_tick_b = (parseString(string, 4) == "") + : RgbColor(rgbStr2Num(str3) >> 16, rgbStr2Num(str3) >> 8, rgbStr2Num(str3)); + rgb_tick_b = str4.isEmpty() ? rgb_tick_b - : RgbColor(rgbStr2Num(parseString(string, 4)) >> 16, rgbStr2Num(parseString(string, 4)) >> 8, rgbStr2Num(parseString(string, 4))); - rgb_h = (parseString(string, 5) == "") + : RgbColor(rgbStr2Num(str4) >> 16, rgbStr2Num(str4) >> 8, rgbStr2Num(str4)); + rgb_h = str5.isEmpty() ? rgb_h - : RgbColor(rgbStr2Num(parseString(string, 5)) >> 16, rgbStr2Num(parseString(string, 5)) >> 8, rgbStr2Num(parseString(string, 5))); - rgb_m = (parseString(string, 6) == "") + : RgbColor(rgbStr2Num(str5) >> 16, rgbStr2Num(str5) >> 8, rgbStr2Num(str5)); + rgb_m = str6.isEmpty() ? rgb_m - : RgbColor(rgbStr2Num(parseString(string, 6)) >> 16, rgbStr2Num(parseString(string, 6)) >> 8, rgbStr2Num(parseString(string, 6))); + : RgbColor(rgbStr2Num(str6) >> 16, rgbStr2Num(str6) >> 8, rgbStr2Num(str6)); - if (parseString(string, 7) != "") { - if (parseString(string, 7) == "off") { + if (!str7.isEmpty()) { + if (str7 == F("off")) { rgb_s_off = true; } else { rgb_s_off = false; rgb_s = - RgbColor(rgbStr2Num(parseString(string, 7)) >> 16, rgbStr2Num(parseString(string, 7)) >> 8, - rgbStr2Num(parseString(string, 7))); + RgbColor(rgbStr2Num(str7) >> 16, rgbStr2Num(str7) >> 8, + rgbStr2Num(str7)); } } if (parseString(string, 8) != "") { hex2rrggbb(parseString(string, 8)); } - # endif // if defined(RGBW) || defined(GRBW) + # endif // if defined(RGBW) || defined(GRBW) } else if (subCommand == F("stop")) { - mode = On; + mode = P128_modetype::On; } else if (subCommand == F("statusrequest")) {} @@ -653,7 +644,7 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, NeoPixelSendStatus(event); } // command neopixel - if (speed == 0) { mode = On; // speed = 0 = stop mode + if (speed == 0) { mode = P128_modetype::On; // speed = 0 = stop mode } speed = (speed > SPEED_MAX || speed < -SPEED_MAX) ? defaultspeed : speed; // avoid invalid values fadetime = (fadetime <= 0) ? 20 : fadetime; @@ -661,76 +652,86 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, return success; } +void P128_data_struct::rgb2colorStr() { + colorStr.clear(); + rgb.R < 16 ? colorStr = F("0") : F(""); + colorStr += formatToHex(rgb.R, {}); + rgb.G < 16 ? colorStr += F("0") : F(""); + colorStr += formatToHex(rgb.G, {}); + rgb.B < 16 ? colorStr += F("0") : F(""); + colorStr += formatToHex(rgb.B, {}); +} + bool P128_data_struct::plugin_fifty_per_second(struct EventStruct *event) { counter20ms++; lastmode = mode; switch (mode) { - case Fade: + case P128_modetype::Fade: fade(); break; - case ColorFade: + case P128_modetype::ColorFade: colorfade(); break; - case Rainbow: + case P128_modetype::Rainbow: rainbow(); break; - case Kitt: + case P128_modetype::Kitt: kitt(); break; - case Comet: + case P128_modetype::Comet: comet(); break; - case Theatre: + case P128_modetype::Theatre: theatre(); break; - case Scan: + case P128_modetype::Scan: scan(); break; - case Dualscan: + case P128_modetype::Dualscan: dualscan(); break; - case Twinkle: + case P128_modetype::Twinkle: twinkle(); break; - case TwinkleFade: + case P128_modetype::TwinkleFade: twinklefade(); break; - case Sparkle: + case P128_modetype::Sparkle: sparkle(); break; - case Fire: + case P128_modetype::Fire: fire(); break; - case FireFlicker: + case P128_modetype::FireFlicker: fire_flicker(); break; - case Wipe: + case P128_modetype::Wipe: wipe(); break; - case Dualwipe: + case P128_modetype::Dualwipe: dualwipe(); break; - case FakeTV: + case P128_modetype::FakeTV: faketv(); break; - case SimpleClock: + case P128_modetype::SimpleClock: Plugin_128_simpleclock(); break; @@ -741,9 +742,9 @@ bool P128_data_struct::plugin_fifty_per_second(struct EventStruct *event) { Plugin_128_pixels->Show(); if (mode != lastmode) { - String log = ""; + String log; log = F("NeoPixelBus: Mode Change: "); - log += modeName[mode]; + log += P128_modeType_toString(mode); addLog(LOG_LEVEL_INFO, log); NeoPixelSendStatus(event); } @@ -768,9 +769,9 @@ void P128_data_struct::fade(void) { # endif // if defined(RGBW) || defined(GRBW) if ((counter20ms > maxtime) && (Plugin_128_pixels->GetPixelColor(pixel).CalculateBrightness() == 0)) { - mode = Off; + mode = P128_modetype::Off; } else if (counter20ms > maxtime) { - mode = On; + mode = P128_modetype::On; } Plugin_128_pixels->SetPixelColor(pixel, updatedColor); @@ -800,7 +801,7 @@ void P128_data_struct::colorfade(void) { Plugin_128_pixels->SetPixelColor((i + startpixel) % pixelCount, updatedColor); } - mode = On; + mode = P128_modetype::On; } void P128_data_struct::wipe(void) { @@ -815,7 +816,7 @@ void P128_data_struct::wipe(void) { if (_counter_mode_step > 0) { Plugin_128_pixels->SetPixelColor(pixelCount - _counter_mode_step, rgb); } } - if (_counter_mode_step == pixelCount) { mode = On; } + if (_counter_mode_step == pixelCount) { mode = P128_modetype::On; } _counter_mode_step++; } } @@ -845,7 +846,7 @@ void P128_data_struct::dualwipe(void) { } if (_counter_mode_step >= pixelCount / 2) { - mode = On; + mode = P128_modetype::On; Plugin_128_pixels->SetPixelColor(_counter_mode_step - 1, rgb); } _counter_mode_step++; @@ -936,7 +937,7 @@ void P128_data_struct::rainbow(void) { uint8_t b1 = (Wheel(((i * 256 / pixelCount) + counter20ms * rainbowspeed / 10) & 255)); Plugin_128_pixels->SetPixelColor(i, RgbColor(r1, g1, b1)); } - mode = (rainbowspeed == 0) ? On : Rainbow; + mode = (rainbowspeed == 0) ? P128_modetype::On : P128_modetype::Rainbow; } /* @@ -1387,36 +1388,41 @@ uint32_t P128_data_struct::rgbStr2Num(String rgbStr) { void P128_data_struct::hex2rgb(String hexcolor) { colorStr = hexcolor; + uint32_t hcolorui = rgbStr2Num(hexcolor); + # if defined(RGBW) || defined(GRBW) hexcolor.length() <= 6 - ? rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) - : rgb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + ? rgb = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui) + : rgb = RgbwColor(hcolorui >> 24, hcolorui >> 16, hcolorui >> 8, hcolorui); # else // if defined(RGBW) || defined(GRBW) - rgb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + rgb = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui); # endif // if defined(RGBW) || defined(GRBW) } void P128_data_struct::hex2rrggbb(String hexcolor) { backgroundcolorStr = hexcolor; + uint32_t hcolorui = rgbStr2Num(hexcolor); + # if defined(RGBW) || defined(GRBW) hexcolor.length() <= 6 - ? rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) - : rrggbb = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + ? rrggbb = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui) + : rrggbb = RgbwColor(hcolorui >> 24, hcolorui >> 16, hcolorui >> 8, hcolorui); # else // if defined(RGBW) || defined(GRBW) - rrggbb = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + rrggbb = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui); # endif // if defined(RGBW) || defined(GRBW) } void P128_data_struct::hex2rgb_pixel(String hexcolor) { colorStr = hexcolor; + uint32_t hcolorui = rgbStr2Num(hexcolor); for (int i = 0; i < pixelCount; i++) { # if defined(RGBW) || defined(GRBW) hexcolor.length() <= 6 - ? rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)) - : rgb_target[i] = RgbwColor(rgbStr2Num(hexcolor) >> 24, rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + ? rgb_target[i] = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui) + : rgb_target[i] = RgbwColor(hcolorui >> 24, hcolorui >> 16, hcolorui >> 8, hcolorui); # else // if defined(RGBW) || defined(GRBW) - rgb_target[i] = RgbColor(rgbStr2Num(hexcolor) >> 16, rgbStr2Num(hexcolor) >> 8, rgbStr2Num(hexcolor)); + rgb_target[i] = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui); # endif // if defined(RGBW) || defined(GRBW) } } @@ -1432,39 +1438,67 @@ void P128_data_struct::NeoPixelSendStatus(struct EventStruct *eventSource) { String json; + json.reserve(285); // Awfully long string :-| + printToWebJSON = true; - json += F("{\n"); - json += F("\"plugin\": \"128"); - json += F("\",\n\"mode\": \""); - json += modeName[mode]; - json += F("\",\n\"lastmode\": \""); - json += modeName[savemode]; - json += F("\",\n\"fadetime\": \""); - json += fadetime; - json += F("\",\n\"fadedelay\": \""); - json += fadedelay; - json += F("\",\n\"dim\": \""); - json += Plugin_128_pixels->GetBrightness(); - json += F("\",\n\"rgb\": \""); - json += colorStr; - json += F("\",\n\"hue\": \""); - json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).H * 360), 0); - json += F("\",\n\"saturation\": \""); - json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).S * 100), 0); - json += F("\",\n\"brightness\": \""); - json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).B * 100), 0); - json += F("\",\n\"bgcolor\": \""); - json += backgroundcolorStr; - json += F("\",\n\"count\": \""); - json += count; - json += F("\",\n\"speed\": \""); - json += speed; - json += F("\",\n\"pixelcount\": \""); - json += pixelCount; - json += F("\"\n}\n"); - SendStatus(eventSource, json); // send http response to controller (JSON format) + json += F("{\n"); // 2 + json += F("\"plugin\": \"128"); // 14 + json += F("\",\n\"mode\": \""); // 12 + json += P128_modeType_toString(mode); // 2-11 + json += F("\",\n\"lastmode\": \""); // 16 + json += P128_modeType_toString(savemode); // 2-11 + json += F("\",\n\"fadetime\": \""); // 16 + json += fadetime; // 1-5 + json += F("\",\n\"fadedelay\": \""); // 16 + json += fadedelay; // 1-5 + json += F("\",\n\"dim\": \""); // 9 + json += Plugin_128_pixels->GetBrightness(); // 1-3 + json += F("\",\n\"rgb\": \""); // 9 + json += colorStr; // 6-8 + json += F("\",\n\"hue\": \""); // 9 + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).H * 360), 0); // 8? + json += F("\",\n\"saturation\": \""); // 18 + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).S * 100), 0); // 8? + json += F("\",\n\"brightness\": \""); // 18 + json += toString((HsbColor(RgbColor(rgb.R, rgb.G, rgb.B)).B * 100), 0); // 8? + json += F("\",\n\"bgcolor\": \""); // 15 + json += backgroundcolorStr; // 6-8 + json += F("\",\n\"count\": \""); // 13 + json += count; // 1-3 + json += F("\",\n\"speed\": \""); // 13 + json += speed; // 1-2 + json += F("\",\n\"pixelcount\": \""); // 18 + json += pixelCount; // 1-3 + json += F("\"\n}\n"); // 4 + SendStatus(eventSource, json); // send http response to controller (JSON format) printToWeb = false; } +const __FlashStringHelper * P128_data_struct::P128_modeType_toString(P128_modetype modeType) { + switch (modeType) { + case P128_modetype::Off: return F("off"); + case P128_modetype::On: return F("on"); + case P128_modetype::Fade: return F("fade"); + case P128_modetype::ColorFade: return F("colorfade"); + case P128_modetype::Rainbow: return F("rainbow"); + case P128_modetype::Kitt: return F("kitt"); + case P128_modetype::Comet: return F("comet"); + case P128_modetype::Theatre: return F("theatre"); + case P128_modetype::Scan: return F("scan"); + case P128_modetype::Dualscan: return F("dualscan"); + case P128_modetype::Twinkle: return F("twinkle"); + case P128_modetype::TwinkleFade: return F("twinklefade"); + case P128_modetype::Sparkle: return F("sparkle"); + case P128_modetype::Fire: return F("fire"); + case P128_modetype::FireFlicker: return F("fireflicker"); + case P128_modetype::Wipe: return F("wipe"); + case P128_modetype::Dualwipe: return F("dualwipe"); + case P128_modetype::FakeTV: return F("faketv"); + + // case P128_modetype::SimpleClock: return F("simpleclock"); + } + return F("*unknown*"); +} + #endif // ifdef USES_P128 diff --git a/src/src/PluginStructs/P128_data_struct.h b/src/src/PluginStructs/P128_data_struct.h index 962206a07..3c164fad7 100644 --- a/src/src/PluginStructs/P128_data_struct.h +++ b/src/src/PluginStructs/P128_data_struct.h @@ -2215,11 +2215,11 @@ const uint8_t PROGMEM ftv_gamma8[] = { # define NEOPIXEL_LIB NeoPixelBrightnessBus // Neopixel library type # if defined(ESP32) -# define METHOD NeoEsp32Rmt1800KbpsMethod // RMT, user selected pin - use NeoEsp32RmtMethod (should also work on ESP32S2) +# define METHOD NeoEsp32Rmt1800KbpsMethod // RMT, user selected pin - use NeoEsp32RmtMethod # endif // if defined(ESP32) # if defined(ESP8266) # define METHOD NeoEsp8266Uart1800KbpsMethod // GPIO2 - use NeoEsp8266Uart0800KbpsMethod for GPIO1(TX) -# endif // if defined(ESP32) +# endif // if defined(ESP8266) # if defined GRB # define FEATURE NeoGrbFeature @@ -2241,7 +2241,7 @@ const uint8_t PROGMEM ftv_gamma8[] = { const float pi = 3.1415926535897932384626433832795; -enum P128_modetype { +enum class P128_modetype { Off, On, Fade, ColorFade, Rainbow, Kitt, Comet, Theatre, Scan, Dualscan, Twinkle, TwinkleFade, Sparkle, Fire, FireFlicker, Wipe, Dualwipe, FakeTV, SimpleClock @@ -2267,14 +2267,14 @@ private: int8_t gpioPin; - uint16_t pos, - color, - r_pixel, - startpixel, - endpixel, - difference, - fps = 50, - colorcount; + uint16_t pos = 0, + color = 0, + r_pixel = 0, + startpixel = 0, + endpixel = 0, + difference = 0, + fps = 50, + colorcount = 0; # if defined(RGBW) || defined(GRBW) RgbwColor rgb_target[ARRAYSIZE], @@ -2307,14 +2307,14 @@ private: rev_intensity = 3; uint32_t _counter_mode_step = 0, - fadetime = 1000, - ftv_holdTime, - pixelNum; + fadetime = 1000u, + ftv_holdTime = 0, + pixelNum = 0; uint16_t ftv_pr = 0, ftv_pg = 0, ftv_pb = 0; // Prev R, G, B; - uint32_t ftv_totalTime, ftv_fadeTime, ftv_startTime, ftv_elapsed; - uint16_t ftv_nr, ftv_ng, ftv_nb, ftv_r, ftv_g, ftv_b, ftv_i, ftv_frac; - uint8_t ftv_hi, ftv_lo, ftv_r8, ftv_g8, ftv_b8; + uint32_t ftv_totalTime = 0, ftv_fadeTime = 0, ftv_startTime = 0, ftv_elapsed = 0; + uint16_t ftv_nr = 0, ftv_ng = 0, ftv_nb = 0, ftv_r = 0, ftv_g = 0, ftv_b = 0, ftv_i = 0, ftv_frac = 0; + uint8_t ftv_hi = 0, ftv_lo = 0, ftv_r8 = 0, ftv_g8 = 0, ftv_b8 = 0; String colorStr, backgroundcolorStr; @@ -2329,13 +2329,15 @@ private: unsigned long counter20ms = 0, starttime[ARRAYSIZE], - starttimerb, - maxtime = 0; + starttimerb = 0, + maxtime = 0; P128_modetype mode = P128_modetype::Off, savemode = P128_modetype::Off, lastmode = P128_modetype::Off; + void rgb2colorStr(); + void fade(void); void colorfade(void); void wipe(void); @@ -2353,12 +2355,14 @@ private: void sparkle(void); // Fire - unsigned long fireTimer; + unsigned long fireTimer = 0; RgbColor leds[ARRAYSIZE]; - void fire(void); + void fire(void); + + const __FlashStringHelper* P128_modeType_toString(P128_modetype modeType); /// random number seed - uint16_t rand16seed; // = RAND16_SEED; + uint16_t rand16seed; // = RAND16_SEED; // leave uninitialized uint8_t random8(); uint8_t random8(uint8_t lim); uint8_t random8(uint8_t min, @@ -2377,12 +2381,6 @@ private: void hex2rrggbb(String hexcolor); void hex2rgb_pixel(String hexcolor); void NeoPixelSendStatus(struct EventStruct *eventSource); - - const char *modeName[19] = { - "off", "on", "fade", "colorfade", "rainbow", "kitt", "comet", - "theatre", "scan", "dualscan", "twinkle", "twinklefade", "sparkle", "fire", - "fireflicker", "wipe", "dualwipe", "faketv", "simpleclock" - }; }; #endif // ifdef USES_P128 From 0a2ffdcc09f493da2221e103bc5e5542f4a926ac Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Wed, 5 Jan 2022 21:37:47 +0100 Subject: [PATCH 005/161] [P128] Forgot some code-debug --- src/src/PluginStructs/P128_data_struct.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/src/PluginStructs/P128_data_struct.cpp b/src/src/PluginStructs/P128_data_struct.cpp index aa91b83fc..6bc9058a2 100644 --- a/src/src/PluginStructs/P128_data_struct.cpp +++ b/src/src/PluginStructs/P128_data_struct.cpp @@ -1495,8 +1495,7 @@ const __FlashStringHelper * P128_data_struct::P128_modeType_toString(P128_modety case P128_modetype::Wipe: return F("wipe"); case P128_modetype::Dualwipe: return F("dualwipe"); case P128_modetype::FakeTV: return F("faketv"); - - // case P128_modetype::SimpleClock: return F("simpleclock"); + case P128_modetype::SimpleClock: return F("simpleclock"); } return F("*unknown*"); } From af7d915bca63d6bc200f43c66f169174a42d96f0 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 6 Jan 2022 20:24:31 +0100 Subject: [PATCH 006/161] [P128] Code optimizations, review feedback --- src/_P128_NeoPixelBusFX.ino | 5 +- src/src/PluginStructs/P128_data_struct.cpp | 183 ++++++++++++--------- src/src/PluginStructs/P128_data_struct.h | 8 +- 3 files changed, 113 insertions(+), 83 deletions(-) diff --git a/src/_P128_NeoPixelBusFX.ino b/src/_P128_NeoPixelBusFX.ino index e4a83c170..dca84abb8 100644 --- a/src/_P128_NeoPixelBusFX.ino +++ b/src/_P128_NeoPixelBusFX.ino @@ -7,6 +7,7 @@ // ####################################################################################################### // Changelog: +// 2022-01-05, tonhuisman Code optimizations and review feedback // 2022-01-04, tonhuisman Code optimizations, reduce calls to parseString and rgbStr2Num, string handling // Ensure no instance is still running when PLUGIN_INIT is called, as it will cause RMT issues // 2022-01-03, tonhuisman Code optimizations, struct variable initialization @@ -14,7 +15,7 @@ // 2022-01-02, tonhuisman Fixed ESP32 related issues (conditional compilation, wrong stripe type) // Add configuration for ESP32 GPIO pin // 2022-01-01, tonhuisman On request migrated from https://github.com/djcysmic/NeopixelBusFX to ESPEasy (that is an -// extension from plugin _P124_NeoPixelBusFX.ini on the ESPEasyPluginPlayground) +// extension from plugin _P124_NeoPixelBusFX.ino on the ESPEasyPluginPlayground) // - Adjusted to work combined with FastLED library (random8() issues) // - Moved firetv.h data to P128_data_struct.h // - Use PCONFIG(0) macro where applicable @@ -186,7 +187,9 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) addRowLabel(formatGpioName_output("Stripe data")); addPinSelect(PinSelectPurpose::Generic_output, F("taskdevicepin1"), PIN(0)); # endif // ifdef ESP32 + addFormNumericBox(F("Led Count"), F("plugin_128_leds"), PCONFIG(0), 1, 999); + success = true; break; } diff --git a/src/src/PluginStructs/P128_data_struct.cpp b/src/src/PluginStructs/P128_data_struct.cpp index 6bc9058a2..c65590cca 100644 --- a/src/src/PluginStructs/P128_data_struct.cpp +++ b/src/src/PluginStructs/P128_data_struct.cpp @@ -202,8 +202,8 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, mode = P128_modetype::Fade; fadedelay = 0; rgb = - RgbColor(HsbColor(str3.toFloat() / 360, str4.toFloat() / 100, - str5.toFloat() / 100)); + RgbColor(HsbColor(str3.toFloat() / 360.0f, str4.toFloat() / 100.0f, + str5.toFloat() / 100.0f)); rgb2colorStr(); @@ -231,8 +231,8 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, else if (subCommand == F("hsvone")) { mode = P128_modetype::On; rgb = - RgbColor(HsbColor(str4.toFloat() / 360, str5.toFloat() / 100, - str6.toFloat() / 100)); + RgbColor(HsbColor(str4.toFloat() / 360.0f, str5.toFloat() / 100.0f, + str6.toFloat() / 100.0f)); rgb2colorStr(); @@ -245,8 +245,8 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, mode = P128_modetype::On; rgb = - RgbColor(HsbColor(str5.toFloat() / 360, str6.toFloat() / 100, - str7.toFloat() / 100)); + RgbColor(HsbColor(str5.toFloat() / 360.0f, str6.toFloat() / 100.0f, + str7.toFloat() / 100.0f)); rgb2colorStr(); @@ -492,58 +492,66 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, # if defined(RGBW) || defined(GRBW) if (!str3.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str3); + if (str3.length() <= 6) { rgb_tick_s = - RgbwColor(rgbStr2Num(str3) >> 16, rgbStr2Num(str3) >> 8, - rgbStr2Num(str3)); + RgbwColor(hcolorui >> 16, hcolorui >> 8, + hcolorui); } else { rgb_tick_s = - RgbwColor(rgbStr2Num(str3) >> 24, - rgbStr2Num(str3) >> 16, - rgbStr2Num(str3) >> 8, - rgbStr2Num(str3)); + RgbwColor(hcolorui >> 24, + hcolorui >> 16, + hcolorui >> 8, + hcolorui); } } if (!str4.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str4); + if (str4.length() <= 6) { rgb_tick_b = - RgbwColor(rgbStr2Num(str4) >> 16, rgbStr2Num(str4) >> 8, - rgbStr2Num(str4)); + RgbwColor(hcolorui >> 16, hcolorui >> 8, + hcolorui); } else { rgb_tick_b = - RgbwColor(rgbStr2Num(str4) >> 24, - rgbStr2Num(str4) >> 16, - rgbStr2Num(str4) >> 8, - rgbStr2Num(str4)); + RgbwColor(hcolorui >> 24, + hcolorui >> 16, + hcolorui >> 8, + hcolorui); } } if (!str5.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str5); + if (str5.length() <= 6) { rgb_h = - RgbwColor(rgbStr2Num(str5) >> 16, rgbStr2Num(str5) >> 8, - rgbStr2Num(str5)); + RgbwColor(hcolorui >> 16, hcolorui >> 8, + hcolorui); } else { rgb_h = - RgbwColor(rgbStr2Num(str5) >> 24, - rgbStr2Num(str5) >> 16, - rgbStr2Num(str5) >> 8, - rgbStr2Num(str5)); + RgbwColor(hcolorui >> 24, + hcolorui >> 16, + hcolorui >> 8, + hcolorui); } } if (!str6.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str6); + if (str6.length() <= 6) { rgb_m = - RgbwColor(rgbStr2Num(str6) >> 16, rgbStr2Num(str6) >> 8, - rgbStr2Num(str6)); + RgbwColor(hcolorui >> 16, hcolorui >> 8, + hcolorui); } else { rgb_m = - RgbwColor(rgbStr2Num(str6) >> 24, - rgbStr2Num(str6) >> 16, - rgbStr2Num(str6) >> 8, - rgbStr2Num(str6)); + RgbwColor(hcolorui >> 24, + hcolorui >> 16, + hcolorui >> 8, + hcolorui); } } @@ -551,53 +559,61 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, if (str7 == F("off")) { rgb_s_off = true; } else if (str7.length() <= 6) { + const uint32_t hcolorui = rgbStr2Num(str7); rgb_s_off = false; rgb_s = - RgbwColor(rgbStr2Num(str7) >> 16, rgbStr2Num(str7) >> 8, - rgbStr2Num(str7)); + RgbwColor(hcolorui >> 16, hcolorui >> 8, + hcolorui); } else { + const uint32_t hcolorui = rgbStr2Num(str7); rgb_s_off = false; rgb_s = - RgbwColor(rgbStr2Num(str7) >> 24, - rgbStr2Num(str7) >> 16, - rgbStr2Num(str7) >> 8, - rgbStr2Num(str7)); + RgbwColor(hcolorui >> 24, + hcolorui >> 16, + hcolorui >> 8, + hcolorui); } } - if (parseString(string, 8) != "") { - hex2rrggbb(parseString(string, 8)); - } - # else // if defined(RGBW) || defined(GRBW) - rgb_tick_s = str3.isEmpty() - ? rgb_tick_s - : RgbColor(rgbStr2Num(str3) >> 16, rgbStr2Num(str3) >> 8, rgbStr2Num(str3)); - rgb_tick_b = str4.isEmpty() - ? rgb_tick_b - : RgbColor(rgbStr2Num(str4) >> 16, rgbStr2Num(str4) >> 8, rgbStr2Num(str4)); - rgb_h = str5.isEmpty() - ? rgb_h - : RgbColor(rgbStr2Num(str5) >> 16, rgbStr2Num(str5) >> 8, rgbStr2Num(str5)); - rgb_m = str6.isEmpty() - ? rgb_m - : RgbColor(rgbStr2Num(str6) >> 16, rgbStr2Num(str6) >> 8, rgbStr2Num(str6)); + if (!str3.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str3); + rgb_tick_s = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui); + } + + if (!str4.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str4); + rgb_tick_b = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui); + } + + if (!str5.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str5); + rgb_h = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui); + } + + if (!str6.isEmpty()) { + const uint32_t hcolorui = rgbStr2Num(str6); + rgb_m = RgbColor(hcolorui >> 16, hcolorui >> 8, hcolorui); + } if (!str7.isEmpty()) { if (str7 == F("off")) { rgb_s_off = true; } else { + const uint32_t hcolorui = rgbStr2Num(str7); rgb_s_off = false; rgb_s = - RgbColor(rgbStr2Num(str7) >> 16, rgbStr2Num(str7) >> 8, - rgbStr2Num(str7)); + RgbColor(hcolorui >> 16, hcolorui >> 8, + hcolorui); } } - if (parseString(string, 8) != "") { hex2rrggbb(parseString(string, 8)); } - # endif // if defined(RGBW) || defined(GRBW) + + if (!parseString(string, 8).isEmpty()) { + hex2rrggbb(parseString(string, 8)); + } } else if (subCommand == F("stop")) { @@ -642,24 +658,35 @@ bool P128_data_struct::plugin_write(struct EventStruct *event, printToWeb = false; } NeoPixelSendStatus(event); - } // command neopixel + } // command neopixel - if (speed == 0) { mode = P128_modetype::On; // speed = 0 = stop mode + if (speed == 0) { + mode = P128_modetype::On; // speed = 0 = stop mode + } + + // avoid invalid values + if ((speed > SPEED_MAX) || (speed < -SPEED_MAX)) { + speed = defaultspeed; + } + + if (fadetime <= 0) { + fadetime = 20; } - speed = (speed > SPEED_MAX || speed < -SPEED_MAX) ? defaultspeed : speed; // avoid invalid values - fadetime = (fadetime <= 0) ? 20 : fadetime; return success; } void P128_data_struct::rgb2colorStr() { colorStr.clear(); - rgb.R < 16 ? colorStr = F("0") : F(""); - colorStr += formatToHex(rgb.R, {}); - rgb.G < 16 ? colorStr += F("0") : F(""); - colorStr += formatToHex(rgb.G, {}); - rgb.B < 16 ? colorStr += F("0") : F(""); - colorStr += formatToHex(rgb.B, {}); + + if (rgb.R < 16) { colorStr += '0'; } + colorStr += formatToHex(rgb.R, {}); + + if (rgb.G < 16) { colorStr += '0'; } + colorStr += formatToHex(rgb.G, {}); + + if (rgb.B < 16) { colorStr += '0'; } + colorStr += formatToHex(rgb.B, {}); } bool P128_data_struct::plugin_fifty_per_second(struct EventStruct *event) { @@ -742,10 +769,12 @@ bool P128_data_struct::plugin_fifty_per_second(struct EventStruct *event) { Plugin_128_pixels->Show(); if (mode != lastmode) { - String log; - log = F("NeoPixelBus: Mode Change: "); - log += P128_modeType_toString(mode); - addLog(LOG_LEVEL_INFO, log); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log = F("NeoPixelBus: Mode Change: "); + log += P128_modeType_toString(mode); + addLog(LOG_LEVEL_INFO, log); + } NeoPixelSendStatus(event); } return true; @@ -1381,14 +1410,14 @@ void P128_data_struct::Plugin_128_simpleclock() { } uint32_t P128_data_struct::rgbStr2Num(String rgbStr) { - uint32_t rgbDec = (int)strtoul(&rgbStr[0], NULL, 16); + uint32_t rgbDec = static_cast(strtoul(&rgbStr[0], NULL, 16)); return rgbDec; } -void P128_data_struct::hex2rgb(String hexcolor) { +void P128_data_struct::hex2rgb(const String& hexcolor) { colorStr = hexcolor; - uint32_t hcolorui = rgbStr2Num(hexcolor); + const uint32_t hcolorui = rgbStr2Num(hexcolor); # if defined(RGBW) || defined(GRBW) hexcolor.length() <= 6 @@ -1399,9 +1428,9 @@ void P128_data_struct::hex2rgb(String hexcolor) { # endif // if defined(RGBW) || defined(GRBW) } -void P128_data_struct::hex2rrggbb(String hexcolor) { +void P128_data_struct::hex2rrggbb(const String& hexcolor) { backgroundcolorStr = hexcolor; - uint32_t hcolorui = rgbStr2Num(hexcolor); + const uint32_t hcolorui = rgbStr2Num(hexcolor); # if defined(RGBW) || defined(GRBW) hexcolor.length() <= 6 @@ -1412,9 +1441,9 @@ void P128_data_struct::hex2rrggbb(String hexcolor) { # endif // if defined(RGBW) || defined(GRBW) } -void P128_data_struct::hex2rgb_pixel(String hexcolor) { +void P128_data_struct::hex2rgb_pixel(const String& hexcolor) { colorStr = hexcolor; - uint32_t hcolorui = rgbStr2Num(hexcolor); + const uint32_t hcolorui = rgbStr2Num(hexcolor); for (int i = 0; i < pixelCount; i++) { # if defined(RGBW) || defined(GRBW) diff --git a/src/src/PluginStructs/P128_data_struct.h b/src/src/PluginStructs/P128_data_struct.h index 3c164fad7..090a5f44d 100644 --- a/src/src/PluginStructs/P128_data_struct.h +++ b/src/src/PluginStructs/P128_data_struct.h @@ -2239,8 +2239,6 @@ const uint8_t PROGMEM ftv_gamma8[] = { # define numPixels (sizeof(ftv_colors) / sizeof(ftv_colors[0])) -const float pi = 3.1415926535897932384626433832795; - enum class P128_modetype { Off, On, Fade, ColorFade, Rainbow, Kitt, Comet, Theatre, Scan, Dualscan, Twinkle, TwinkleFade, Sparkle, Fire, @@ -2377,9 +2375,9 @@ private: void fire_flicker(); void Plugin_128_simpleclock(); uint32_t rgbStr2Num(String rgbStr); - void hex2rgb(String hexcolor); - void hex2rrggbb(String hexcolor); - void hex2rgb_pixel(String hexcolor); + void hex2rgb(const String& hexcolor); + void hex2rrggbb(const String& hexcolor); + void hex2rgb_pixel(const String& hexcolor); void NeoPixelSendStatus(struct EventStruct *eventSource); }; #endif // ifdef USES_P128 From 115edfa909213699631cfecc63942bda5e5b73c3 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 8 Jan 2022 12:19:02 +0100 Subject: [PATCH 007/161] [P128] Small UI fixes while writing documentation --- src/_P128_NeoPixelBusFX.ino | 14 ++++++++------ src/src/PluginStructs/P128_data_struct.h | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/_P128_NeoPixelBusFX.ino b/src/_P128_NeoPixelBusFX.ino index dca84abb8..91e3384a1 100644 --- a/src/_P128_NeoPixelBusFX.ino +++ b/src/_P128_NeoPixelBusFX.ino @@ -7,6 +7,8 @@ // ####################################################################################################### // Changelog: +// 2022-01-08, tonhuisman Small UI fixes while writing documentation. +// 2022-01-06, tonhuisman Move from Development to Testing // 2022-01-05, tonhuisman Code optimizations and review feedback // 2022-01-04, tonhuisman Code optimizations, reduce calls to parseString and rgbStr2Num, string handling // Ensure no instance is still running when PLUGIN_INIT is called, as it will cause RMT issues @@ -117,7 +119,7 @@ # define PLUGIN_128 # define PLUGIN_ID_128 128 -# define PLUGIN_NAME_128 "Output - NeoPixel (BusFX) [DEVELOPMENT]" +# define PLUGIN_NAME_128 "Output - NeoPixel (BusFX) [TESTING]" # define PLUGIN_VALUENAME1_128 "Mode" # define PLUGIN_VALUENAME2_128 "Lastmode" # define PLUGIN_VALUENAME3_128 "Fadetime" @@ -179,16 +181,16 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_LOAD: { addFormSubHeader(F("Actuator")); + + addRowLabel(formatGpioName_output("Stripe data")); # ifdef ESP8266 - addRowLabel(F("")); addHtml(F("Please connect stripe to GPIO2!")); # endif // ifdef ESP8266 # ifdef ESP32 - addRowLabel(formatGpioName_output("Stripe data")); addPinSelect(PinSelectPurpose::Generic_output, F("taskdevicepin1"), PIN(0)); # endif // ifdef ESP32 - addFormNumericBox(F("Led Count"), F("plugin_128_leds"), PCONFIG(0), 1, 999); + addFormNumericBox(F("Led Count"), F("plugin_128_leds"), P128_CONFIG_LED_COUNT, 1, 999); success = true; break; @@ -196,7 +198,7 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_SAVE: { - PCONFIG(0) = getFormItemInt(F("plugin_128_leds")); + P128_CONFIG_LED_COUNT = getFormItemInt(F("plugin_128_leds")); # ifdef ESP32 PIN(0) = getFormItemInt(F("taskdevicepin1")); @@ -215,7 +217,7 @@ boolean Plugin_128(uint8_t function, struct EventStruct *event, String& string) clearPluginTaskData(event->TaskIndex); } - initPluginTaskData(event->TaskIndex, new (std::nothrow) P128_data_struct(PIN(0), PCONFIG(0))); + initPluginTaskData(event->TaskIndex, new (std::nothrow) P128_data_struct(PIN(0), P128_CONFIG_LED_COUNT)); P128_data_struct *P128_data = static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr == P128_data) { diff --git a/src/src/PluginStructs/P128_data_struct.h b/src/src/PluginStructs/P128_data_struct.h index 090a5f44d..8058ae398 100644 --- a/src/src/PluginStructs/P128_data_struct.h +++ b/src/src/PluginStructs/P128_data_struct.h @@ -2201,6 +2201,8 @@ const uint8_t PROGMEM ftv_gamma8[] = { # include # include "../../ESPEasy-Globals.h" +# define P128_CONFIG_LED_COUNT PCONFIG(0) + # define SPEED_MAX 50 # define ARRAYSIZE 300 // Max LED Count From 462e3242037a8b58856b48184fc2598a2b8981a5 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 8 Jan 2022 12:20:25 +0100 Subject: [PATCH 008/161] [P128] Add plugin documentation --- docs/source/Plugin/P128.rst | 93 +++++++++ .../Plugin/P128_DeviceConfiguration.png | Bin 0 -> 29627 bytes docs/source/Plugin/P128_GPIO_ESP8266.png | Bin 0 -> 4150 bytes docs/source/Plugin/P128_commands.repl | 179 ++++++++++++++++++ docs/source/Plugin/_Plugin.rst | 1 + docs/source/Plugin/_plugin_categories.repl | 2 +- .../Plugin/_plugin_substitutions_p12x.repl | 13 ++ 7 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 docs/source/Plugin/P128.rst create mode 100644 docs/source/Plugin/P128_DeviceConfiguration.png create mode 100644 docs/source/Plugin/P128_GPIO_ESP8266.png create mode 100644 docs/source/Plugin/P128_commands.repl diff --git a/docs/source/Plugin/P128.rst b/docs/source/Plugin/P128.rst new file mode 100644 index 000000000..08317b5f8 --- /dev/null +++ b/docs/source/Plugin/P128.rst @@ -0,0 +1,93 @@ +.. include:: ../Plugin/_plugin_substitutions_p12x.repl +.. _P128_page: + +|P128_typename| +================================================== + +|P128_shortinfo| + +Plugin details +-------------- + +Type: |P128_type| + +Name: |P128_name| + +Status: |P128_status| + +GitHub: |P128_github|_ + +Maintainer: |P128_maintainer| + +Used libraries: |P128_usedlibraries| + +Description +----------- + +The NeoPixel (BusFX) plugin is designed to use strings of NeoPixel LEDs, like the WS2811/WS2812/WS2813, to show light-effects. + +Supported hardware +------------------ + +LED strips (sometimes called stripes) using the WS281x type (and clones) of multi-color LEDs, capable of displaying 24 bits of color (16 million colors). Each LED is separately addressable, and the entire stripe can be controlled using a single GPIO pin on the ESP. + +|P128_usedby| + +Configuration +------------- + +.. image:: P128_DeviceConfiguration.png + :alt: Device Configuration + +* **Name** A unique name should be entered here. + +* **Enabled** The device can be disabled or enabled. When not enabled the device should not use any resources. + +Actuator +^^^^^^^^ + +* **GPIO -> Stripe data**: Select the GPIO pin the stripe is connected to (Only available on ESP32!) + +Due to the design of the used library and the methods used, on ESP8266 only GPIO-2 can be used to connect the LED stripe: + +.. image:: P128_GPIO_ESP8266.png + :alt: ESP8266 GPIO instruction + +* **Led Count**: Set up the number of leds that are available on the stripe. (Current maximum is 300). + +Data Aquisition +^^^^^^^^^^^^^^^ + +The Data Acquisition, Send to Controller and Interval settings are standard available configuration items. Send to Controller only when one or more Controllers are configured. + +**Interval** By default, Interval will be set to 0 sec. This is optional. When set, the **Values** will be sent to any configured controllers, and events generated to be handled in rules. + +Values +^^^^^^ + +The value names are fixed and not configurable. These names are: + +* **Mode**: The currently active **mode** (numeric value) +* **Lastmode**: The previously active mode (numeric value) +* **Fadetime**: Currently set fade time value (milliseconds) +* **Fadedelay**: The delay time used during fade in or out (milliseconds) + + +Commands available +^^^^^^^^^^^^^^^^^^ + +.. include:: P128_commands.repl + +Change log +---------- + +.. versionadded:: 2.0 + ... + + |added| + Initial release version. + + + + + diff --git a/docs/source/Plugin/P128_DeviceConfiguration.png b/docs/source/Plugin/P128_DeviceConfiguration.png new file mode 100644 index 0000000000000000000000000000000000000000..7510c8264e2af94c6afe2bc9e30e7d736584d6d9 GIT binary patch literal 29627 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 literal 0 HcmV?d00001 diff --git a/docs/source/Plugin/P128_commands.repl b/docs/source/Plugin/P128_commands.repl new file mode 100644 index 000000000..9f6e18db4 --- /dev/null +++ b/docs/source/Plugin/P128_commands.repl @@ -0,0 +1,179 @@ +.. csv-table:: + :header: "Command Syntax", "Extra information" + :widths: 20, 30 + + " + NB: The ``neopixelfx`` command can be abbreviated to ``nfx``. + "," + " + | For brevity, the ``nfx`` command is used here. + + | Led count == Number of pixels. + " + | ``nfx off [fadetime] [delay]`` + "," + | Switches the stripe off, using the optional fadetime and delay timings (milliseconds). + " + " + | ``nfx on [fadetime] [delay]`` + "," + | Restores the last state of the stripe, active before a ``nfx off`` command was applied, using the optional fadetime and delay timings (milliseconds). + " + " + | ``nfx dim [dimvalue]`` + "," + | Set the brightness of the stripe, range ``0`` to ``255`` (max. brightness), set to 0 when not specified. + " + " + | ``nfx line `` + "," + | Light up the pixels from startpixel (range: 1..number of pixels) to endpixel (range: number of pixels..startpixel) with the specified color. Color is to be specified in a hex RRGGBB value. + " + " + | ``nfx hsvline `` + "," + | Light up the pixels from startpixel (range: 1..number of pixels) to endpixel (range: number of pixels..startpixel) with the specified hsvcolor values. + " + " + | ``nfx one `` + "," + | Light up 1 pixel (range: 1..number of pixels) with the specified color. Color is to be specified in a hex RRGGBB value. + " + " + | ``nfx hsvone `` + "," + | Light up 1 pixel (range: 1..number of pixels) with the specified hsvcolor values. + " + " + | ``nfx all [fadetime] [delay]`` + + | ``nfx rgb [fadetime] [delay]`` + + | ``nfx fade [fadetime] [delay]`` + "," + | Light up all pixels with the specified color, using the optional fadetime and delay timings (milliseconds). Color is to be specified in a hex RRGGBB value. + + | For the ``all`` and ``rgb`` subcommands, the delay is set to 0 if not specified. When using the ``fade`` subcommand, a previously set delay is used. + " + " + | ``nfx hsv [fadetime] [delay]`` + "," + | Light up all pixels with the specified hsvcolor values, using the optional fadetime and delay timings (milliseconds). + + | Delay is set to 0 if not specified. + " + " + | ``nfx colorfade [startpixel] [endpixel]`` + "," + | Change the color for all or specified start- to end-pixels, from startcolor to endcolor. Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx rainbow [speed] [fadetime]`` + "," + | Run a rainbow effect color loop effect using speed and fadetime timings (in milliseconds). + " + " + | ``nfx kitt [speed]`` + "," + | Run a ``kitt`` (from the TV-series Knight Rider) effect across the pixels, using an optional speed value (range: -50..50, default: 25, negative = reverse). + " + " + | ``nfx comet [speed]`` + "," + | Run a comet effect across the pixels, using an optional speed value (range: -50..50, default: 25, negative = reverse). + " + " + | ``nfx theatre [backgroundcolor] [count] [speed]`` + "," + | Run a theatre effect across the pixels, using optional backgroundcolor, count (default: 1) and speed values (range: -50..50, default: 25, negative = reverse). Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx scan [backgroundcolor] [speed]`` + "," + | Run a scan effect across the pixels, using optional backgroundcolor and speed values (range: -50..50, default: 25, negative = reverse). Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx dualscan [backgroundcolor] [speed]`` + "," + | Run a dual scan effect, 2 scans in opposite direction, across the pixels, using optional backgroundcolor and speed values (range: -50..50, default: 25, negative = reverse). Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx twinkle [backgroundcolor] [speed]`` + "," + | Run a twinkle effect across the pixels, using optional backgroundcolor and speed values (range: -50..50, default: 25, negative = reverse). Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx twinklefade [count] [speed]`` + "," + | Run a fading twinkle effect across the pixels, using optional count (default: 1) and speed values (range: -50..50, default: 25, negative = reverse). Color is to be specified in a hex RRGGBB value. + " + " + | ``nfx sparkle [backgroundcolor] [speed]`` + "," + | Run a sparkle effect across the pixels, using optional backgroundcolor and speed values (range: -50..50, default: 25, negative = reverse). Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx wipe [dotcolor] [speed]`` + "," + | Run a wipe effect across the pixels, using optional dotcolor and speed values (range: -50..50, default: 25, negative = reverse). Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx dualwipe [dotcolor] [speed]`` + "," + | Run a dual wipe effect, in opposite direction, across the pixels, using optional dotcolor and speed values (range: -50..50, default: 25, negative = reverse). Colors are to be specified in a hex RRGGBB value. + " + " + | ``nfx fire [fps] [brightness] [cooling] [sparking]`` + "," + | Run a fire effect accross the pixels, with optional fps (default: 50), brightness (default: 31), cooling (range 20..100, default: 50) and sparking (range: 20..200, default: 120) values. + " + " + | ``nfx fireflicker [intensity] [speed]`` + "," + | Run a flickering fire effect across the pixels, with optional intensity (default: 3) and speed (range -50..50, default: 25, negative = reverse) values. + " + " + | ``nfx faketv [startpixel] [endpixel]`` + "," + | Run a fake TV effect on the pixels, optionally specifying a start- end end-pixel. Used for simulating an active TV-set, f.e. when not at home during the evening, to scare off potential burglars. + " + " + | ``nfx simpleclock [bigtickcolor] [smalltickcolor] [hourcolor] [minutecolor] [secondcolor, set 'off' to disable] [backgroundcolor]`` + "," + | Display a simple clock on the pixels. TODO: Optional arguments and setup to be determined. + " + " + | ``nfx stop`` + "," + | Stops the effect. + " + " + | ``nfx statusrequest`` + "," + | Send back the status as a JSON message to the source it was requested from. + " + " + | ``nfx fadetime