Browse Source

Merge branch 'dev' into softcfg

v2
Xose Pérez 6 years ago
parent
commit
2e7e03a1df
39 changed files with 1660 additions and 1349 deletions
  1. +2
    -2
      .github/stale.yml
  2. +1
    -1
      README.md
  3. +21
    -10
      code/build.sh
  4. +76
    -59
      code/espurna/api.ino
  5. +1
    -1
      code/espurna/config/all.h
  6. +2
    -1
      code/espurna/config/arduino.h
  7. +1
    -1
      code/espurna/config/defaults.h
  8. +24
    -4
      code/espurna/config/general.h
  9. +92
    -8
      code/espurna/config/hardware.h
  10. +19
    -12
      code/espurna/config/progmem.h
  11. +2
    -0
      code/espurna/config/prototypes.h
  12. +44
    -24
      code/espurna/config/sensors.h
  13. +32
    -33
      code/espurna/config/types.h
  14. +1
    -1
      code/espurna/config/version.h
  15. BIN
      code/espurna/data/index.all.html.gz
  16. BIN
      code/espurna/data/index.sensor.html.gz
  17. +1
    -1
      code/espurna/eeprom.ino
  18. +1
    -1
      code/espurna/hardware.ino
  19. +4
    -4
      code/espurna/homeassistant.ino
  20. +2
    -2
      code/espurna/i2c.ino
  21. +58
    -55
      code/espurna/ir.ino
  22. +1
    -1
      code/espurna/led.ino
  23. +8
    -2
      code/espurna/ota.ino
  24. +9
    -10
      code/espurna/relay.ino
  25. +106
    -78
      code/espurna/sensor.ino
  26. +6
    -6
      code/espurna/sensors/BaseSensor.h
  27. +1
    -1
      code/espurna/sensors/DHTSensor.h
  28. +3
    -3
      code/espurna/sensors/EmonSensor.h
  29. +29
    -12
      code/espurna/sensors/EventSensor.h
  30. +38
    -11
      code/espurna/sensors/PMSX003Sensor.h
  31. +39
    -32
      code/espurna/sensors/SonarSensor.h
  32. +1
    -1
      code/espurna/ssdp.ino
  33. +655
    -655
      code/espurna/static/index.all.html.gz.h
  34. +298
    -298
      code/espurna/static/index.sensor.html.gz.h
  35. +27
    -5
      code/espurna/web.ino
  36. +4
    -1
      code/extra_scripts.py
  37. +4
    -3
      code/html/custom.js
  38. +2
    -4
      code/memanalyzer.py
  39. +45
    -6
      code/platformio.ini

+ 2
- 2
.github/stale.yml View File

@ -1,9 +1,9 @@
# Number of days of inactivity before an Issue or Pull Request becomes stale # Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 120
daysUntilStale: 60
# Number of days of inactivity before a stale Issue or Pull Request is closed. # Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 30
daysUntilClose: 7
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels: exemptLabels:


+ 1
- 1
README.md View File

@ -3,7 +3,7 @@
ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smart switches, lights and sensors. ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smart switches, lights and sensors.
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries. It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
[![version](https://img.shields.io/badge/version-1.13.2a-brightgreen.svg)](CHANGELOG.md)
[![version](https://img.shields.io/badge/version-1.13.2c-brightgreen.svg)](CHANGELOG.md)
[![branch](https://img.shields.io/badge/branch-softcfg-orange.svg)](https://github.com/xoseperez/espurna/tree/softcfg/) [![branch](https://img.shields.io/badge/branch-softcfg-orange.svg)](https://github.com/xoseperez/espurna/tree/softcfg/)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=softcfg)](https://travis-ci.org/xoseperez/espurna) [![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=softcfg)](https://travis-ci.org/xoseperez/espurna)
[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/softcfg.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard) [![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/softcfg.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard)


+ 21
- 10
code/build.sh View File

@ -1,19 +1,26 @@
#!/bin/bash #!/bin/bash
set -e set -e
# Utility
is_git() {
command -v git >/dev/null 2>&1 || return 1
command git rev-parse >/dev/null 2>&1 || return 1
return 0
}
# Script settings # Script settings
version=$(grep APP_VERSION espurna/config/version.h | awk '{print $3}' | sed 's/"//g') version=$(grep APP_VERSION espurna/config/version.h | awk '{print $3}' | sed 's/"//g')
(command -v git && git rev-parse --is-inside-work-tree) 2>&1>/dev/null
if [ $? -eq 0 ]; then
if is_git; then
git_revision=$(git rev-parse --short HEAD) git_revision=$(git rev-parse --short HEAD)
git_version=$(git describe --tags)
git_version=${version}-${git_revision}
else else
git_revision= git_revision=
git_version=$version git_version=$version
fi fi
par_build=0
par_build=false
par_thread=${BUILDER_THREAD:-0} par_thread=${BUILDER_THREAD:-0}
par_total_threads=${BUILDER_TOTAL_THREADS:-4} par_total_threads=${BUILDER_TOTAL_THREADS:-4}
if [ ${par_thread} -ne ${par_thread} -o \ if [ ${par_thread} -ne ${par_thread} -o \
@ -27,8 +34,12 @@ if [ ${par_thread} -ge ${par_total_threads} ]; then
fi fi
# Available environments # Available environments
travis=$(grep env: platformio.ini | grep travis | sed 's/\[env://' | sed 's/\]/ /' | sort)
available=$(grep env: platformio.ini | grep -v ota | grep -v ssl | grep -v travis | sed 's/\[env://' | sed 's/\]/ /' | sort)
list_envs() {
grep env: platformio.ini | sed 's/\[env:\(.*\)\]/\1/g'
}
travis=$(list_envs | grep travis | sort)
available=$(list_envs | grep -Ev -- '-ota$|-ssl$|^travis' | sort)
# Build tools settings # Build tools settings
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DAPP_REVISION='\"$git_revision\"'" export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DAPP_REVISION='\"$git_revision\"'"
@ -52,7 +63,7 @@ print_environments() {
set_default_environments() { set_default_environments() {
# Hook to build in parallel when using travis # Hook to build in parallel when using travis
if [[ "${TRAVIS_BUILD_STAGE_NAME}" = "Release" ]] && [ ${par_build} ]; then
if [[ "${TRAVIS_BUILD_STAGE_NAME}" = "Release" ]] && ${par_build}; then
environments=$(echo ${available} | \ environments=$(echo ${available} | \
awk -v par_thread=${par_thread} -v par_total_threads=${par_total_threads} \ awk -v par_thread=${par_thread} -v par_total_threads=${par_total_threads} \
'{ for (i = 1; i <= NF; i++) if (++j % par_total_threads == par_thread ) print $i; }') '{ for (i = 1; i <= NF; i++) if (++j % par_total_threads == par_thread ) print $i; }')
@ -90,7 +101,7 @@ build_environments() {
for environment in $environments; do for environment in $environments; do
echo -n "* espurna-$version-$environment.bin --- " echo -n "* espurna-$version-$environment.bin --- "
platformio run --silent --environment $environment || exit 1
platformio run --silent --environment $environment 2>/dev/null || exit 1
stat -c %s .pioenvs/$environment/firmware.bin stat -c %s .pioenvs/$environment/firmware.bin
[[ "${TRAVIS_BUILD_STAGE_NAME}" = "Test" ]] || \ [[ "${TRAVIS_BUILD_STAGE_NAME}" = "Test" ]] || \
mv .pioenvs/$environment/firmware.bin ../firmware/espurna-$version/espurna-$version-$environment.bin mv .pioenvs/$environment/firmware.bin ../firmware/espurna-$version/espurna-$version-$environment.bin
@ -106,7 +117,7 @@ while getopts "lp" opt; do
exit exit
;; ;;
p) p)
par_build=1
par_build=true
;; ;;
esac esac
done done
@ -125,7 +136,7 @@ if [ $# -eq 0 ]; then
set_default_environments set_default_environments
fi fi
if [[ "${CI}" = true ]]; then
if ${CI:-false}; then
print_environments print_environments
fi fi


+ 76
- 59
code/espurna/api.ino View File

@ -72,52 +72,6 @@ bool _asJson(AsyncWebServerRequest *request) {
return asJson; return asJson;
} }
ArRequestHandlerFunction _bindAPI(unsigned int apiID) {
return [apiID](AsyncWebServerRequest *request) {
webLog(request);
if (!_authAPI(request)) return;
web_api_t api = _apis[apiID];
// Check if its a PUT
if (api.putFn != NULL) {
if (request->hasParam("value", request->method() == HTTP_PUT)) {
AsyncWebParameter* p = request->getParam("value", request->method() == HTTP_PUT);
(api.putFn)((p->value()).c_str());
}
}
// Get response from callback
char value[API_BUFFER_SIZE] = {0};
(api.getFn)(value, API_BUFFER_SIZE);
// The response will be a 404 NOT FOUND if the resource is not available
if (0 == value[0]) {
DEBUG_MSG_P(PSTR("[API] Sending 404 response\n"));
request->send(404);
return;
}
DEBUG_MSG_P(PSTR("[API] Sending response '%s'\n"), value);
// Format response according to the Accept header
if (_asJson(request)) {
char buffer[64];
if (isNumber(value)) {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": %s }"), api.key, value);
} else {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": \"%s\" }"), api.key, value);
}
request->send(200, "application/json", buffer);
} else {
request->send(200, "text/plain", value);
}
};
}
void _onAPIs(AsyncWebServerRequest *request) { void _onAPIs(AsyncWebServerRequest *request) {
webLog(request); webLog(request);
@ -174,35 +128,98 @@ void _onRPC(AsyncWebServerRequest *request) {
} }
bool _apiRequestCallback(AsyncWebServerRequest *request) {
String url = request->url();
// Main API entry point
if (url.equals("/api") || url.equals("/apis")) {
_onAPIs(request);
return true;
}
// Main RPC entry point
if (url.equals("/rpc")) {
_onRPC(request);
return true;
}
// Not API request
if (!url.startsWith("/api/")) return false;
for (unsigned char i=0; i < _apis.size(); i++) {
// Search API url
web_api_t api = _apis[i];
if (!url.endsWith(api.key)) continue;
// Log and check credentials
webLog(request);
if (!_authAPI(request)) return false;
// Check if its a PUT
if (api.putFn != NULL) {
if (request->hasParam("value", request->method() == HTTP_PUT)) {
AsyncWebParameter* p = request->getParam("value", request->method() == HTTP_PUT);
(api.putFn)((p->value()).c_str());
}
}
// Get response from callback
char value[API_BUFFER_SIZE] = {0};
(api.getFn)(value, API_BUFFER_SIZE);
// The response will be a 404 NOT FOUND if the resource is not available
if (0 == value[0]) {
DEBUG_MSG_P(PSTR("[API] Sending 404 response\n"));
request->send(404);
return false;
}
DEBUG_MSG_P(PSTR("[API] Sending response '%s'\n"), value);
// Format response according to the Accept header
if (_asJson(request)) {
char buffer[64];
if (isNumber(value)) {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": %s }"), api.key, value);
} else {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": \"%s\" }"), api.key, value);
}
request->send(200, "application/json", buffer);
} else {
request->send(200, "text/plain", value);
}
return true;
}
return false;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void apiRegister(const char * key, api_get_callback_f getFn, api_put_callback_f putFn) { void apiRegister(const char * key, api_get_callback_f getFn, api_put_callback_f putFn) {
// Store it // Store it
web_api_t api; web_api_t api;
char buffer[40];
snprintf_P(buffer, sizeof(buffer), PSTR("/api/%s"), key);
api.key = strdup(key); api.key = strdup(key);
api.getFn = getFn; api.getFn = getFn;
api.putFn = putFn; api.putFn = putFn;
_apis.push_back(api); _apis.push_back(api);
// Bind call
unsigned int methods = HTTP_GET;
if (putFn != NULL) methods += HTTP_PUT;
webServer()->on(buffer, methods, _bindAPI(_apis.size() - 1));
}
bool apiRealTime() {
return getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
} }
void apiSetup() { void apiSetup() {
webServer()->on("/apis", HTTP_GET, _onAPIs);
webServer()->on("/rpc", HTTP_GET, _onRPC);
wsOnSendRegister(_apiWebSocketOnSend);
settingsRegisterKeyCheck(_apiKeyCheck); settingsRegisterKeyCheck(_apiKeyCheck);
}
bool apiRealTime() {
return getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
webRequestRegister(_apiRequestCallback);
wsOnSendRegister(_apiWebSocketOnSend);
} }
#endif // WEB_SUPPORT #endif // WEB_SUPPORT

+ 1
- 1
code/espurna/config/all.h View File

@ -29,9 +29,9 @@
#include "hardware.h" #include "hardware.h"
#include "defaults.h" #include "defaults.h"
#include "general.h" #include "general.h"
#include "dependencies.h"
#include "prototypes.h" #include "prototypes.h"
#include "sensors.h" #include "sensors.h"
#include "dependencies.h"
#include "progmem.h" #include "progmem.h"
#include "debug.h" #include "debug.h"


+ 2
- 1
code/espurna/config/arduino.h View File

@ -8,6 +8,7 @@
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
//#define NODEMCU_LOLIN //#define NODEMCU_LOLIN
//#define WEMOS_D1_MINI
//#define WEMOS_D1_MINI_RELAYSHIELD //#define WEMOS_D1_MINI_RELAYSHIELD
//#define TINKERMAN_ESPURNA_H06 //#define TINKERMAN_ESPURNA_H06
//#define TINKERMAN_ESPURNA_H08 //#define TINKERMAN_ESPURNA_H08
@ -140,7 +141,6 @@
//#define EMON_ANALOG_SUPPORT 1 //#define EMON_ANALOG_SUPPORT 1
//#define EVENTS_SUPPORT 1 //#define EVENTS_SUPPORT 1
//#define GUVAS12SD_SUPPORT 1 //#define GUVAS12SD_SUPPORT 1
//#define HCSR04_SUPPORT 1
//#define HLW8012_SUPPORT 1 //#define HLW8012_SUPPORT 1
//#define MHZ19_SUPPORT 1 //#define MHZ19_SUPPORT 1
//#define NTC_SUPPORT 1 //#define NTC_SUPPORT 1
@ -148,6 +148,7 @@
//#define PZEM004T_SUPPORT 1 //#define PZEM004T_SUPPORT 1
//#define SHT3X_I2C_SUPPORT 1 //#define SHT3X_I2C_SUPPORT 1
//#define SI7021_SUPPORT 1 //#define SI7021_SUPPORT 1
//#define SONAR_SUPPORT 1
//#define TMP3X_SUPPORT 1 //#define TMP3X_SUPPORT 1
//#define V9261F_SUPPORT 1 //#define V9261F_SUPPORT 1
//#define GEIGER_SUPPORT 1 //#define GEIGER_SUPPORT 1

+ 1
- 1
code/espurna/config/defaults.h View File

@ -2,7 +2,7 @@
// Hardware default values // Hardware default values
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#define GPIO_NONE 0x99
#define GPIO_NONE 0xFF
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Buttons // Buttons


+ 24
- 4
code/espurna/config/general.h View File

@ -259,6 +259,14 @@
#define RELAY_SAVE_DELAY 1000 #define RELAY_SAVE_DELAY 1000
#endif #endif
// Configure the MQTT payload for ON/OFF
#ifndef RELAY_MQTT_ON
#define RELAY_MQTT_ON "1"
#endif
#ifndef RELAY_MQTT_OFF
#define RELAY_MQTT_OFF "0"
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// WIFI // WIFI
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -693,6 +701,7 @@
#define MQTT_TOPIC_BOARD "board" #define MQTT_TOPIC_BOARD "board"
#define MQTT_TOPIC_PULSE "pulse" #define MQTT_TOPIC_PULSE "pulse"
#define MQTT_TOPIC_SPEED "speed" #define MQTT_TOPIC_SPEED "speed"
#define MQTT_TOPIC_IR "ir"
// Light module // Light module
#define MQTT_TOPIC_CHANNEL "channel" #define MQTT_TOPIC_CHANNEL "channel"
@ -865,6 +874,14 @@
#define HOMEASSISTANT_ENABLED 0 // Integration not enabled by default #define HOMEASSISTANT_ENABLED 0 // Integration not enabled by default
#define HOMEASSISTANT_PREFIX "homeassistant" // Default MQTT prefix #define HOMEASSISTANT_PREFIX "homeassistant" // Default MQTT prefix
#ifndef HOMEASSISTANT_PAYLOAD_ON
#define HOMEASSISTANT_PAYLOAD_ON "1" // Payload for ON and available messages
#endif
#ifndef HOMEASSISTANT_PAYLOAD_OFF
#define HOMEASSISTANT_PAYLOAD_OFF "0" // Payload for OFF and unavailable messages
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// INFLUXDB // INFLUXDB
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -1020,7 +1037,6 @@
#define RF_RECEIVE_DELAY 500 // Interval between recieving in ms (avoid debouncing) #define RF_RECEIVE_DELAY 500 // Interval between recieving in ms (avoid debouncing)
#endif #endif
#ifndef RF_RAW_SUPPORT #ifndef RF_RAW_SUPPORT
#define RF_RAW_SUPPORT 0 // RF raw codes require a specific firmware for the EFM8BB1 #define RF_RAW_SUPPORT 0 // RF raw codes require a specific firmware for the EFM8BB1
// https://github.com/rhx/RF-Bridge-EFM8BB1 // https://github.com/rhx/RF-Bridge-EFM8BB1
@ -1035,8 +1051,8 @@
#define IR_SUPPORT 0 // Do not build with IR support by default (10.25Kb) #define IR_SUPPORT 0 // Do not build with IR support by default (10.25Kb)
#endif #endif
#ifndef IR_PIN
#define IR_PIN 4 // IR LED
#ifndef IR_RECEIVER_PIN
#define IR_RECEIVER_PIN 4 // IR LED
#endif #endif
// 24 Buttons Set of the IR Remote // 24 Buttons Set of the IR Remote
@ -1044,6 +1060,10 @@
#define IR_BUTTON_SET 1 // IR button set to use (see below) #define IR_BUTTON_SET 1 // IR button set to use (see below)
#endif #endif
#ifndef IR_DEBOUNCE
#define IR_DEBOUNCE 500 // IR debounce time in milliseconds
#endif
//Remote Buttons SET 1 (for the original Remote shipped with the controller) //Remote Buttons SET 1 (for the original Remote shipped with the controller)
#if IR_SUPPORT #if IR_SUPPORT
#if IR_BUTTON_SET == 1 #if IR_BUTTON_SET == 1
@ -1066,7 +1086,7 @@
#define IR_BUTTON_COUNT 24 #define IR_BUTTON_COUNT 24
const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
const uint32_t IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xFF906F, IR_BUTTON_MODE_BRIGHTER, 1 }, { 0xFF906F, IR_BUTTON_MODE_BRIGHTER, 1 },
{ 0xFFB847, IR_BUTTON_MODE_BRIGHTER, 0 }, { 0xFFB847, IR_BUTTON_MODE_BRIGHTER, 0 },


+ 92
- 8
code/espurna/config/hardware.h View File

@ -65,6 +65,26 @@
#include "devices/002_nodemcu_lolin.json.h" #include "devices/002_nodemcu_lolin.json.h"
#elif defined(WEMOS_D1_MINI)
// Info
#define MANUFACTURER "WEMOS"
#define DEVICE "D1_MINI"
// Buttons
// No buttons on the D1 MINI alone, but defining it without adding a button doen't create problems
#define BUTTON1_PIN 0 // Connect a pushbutton between D3 and GND,
// it's the same as using a Wemos one button shield
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1
// LEDs
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
#define I2C_SDA_PIN 4 // D2
#define I2C_SCL_PIN 5 // D1
#elif defined(WEMOS_D1_MINI_RELAYSHIELD) #elif defined(WEMOS_D1_MINI_RELAYSHIELD)
#include "devices/003_wemos_d1_mini_relayshield.json.h" #include "devices/003_wemos_d1_mini_relayshield.json.h"
@ -982,7 +1002,7 @@
// IR // IR
#define IR_SUPPORT 1 #define IR_SUPPORT 1
#define IR_PIN 4
#define IR_RECEIVER_PIN 4
#define IR_BUTTON_SET 1 #define IR_BUTTON_SET 1
#elif defined(MAGICHOME_LED_CONTROLLER_20) #elif defined(MAGICHOME_LED_CONTROLLER_20)
@ -1011,7 +1031,7 @@
// IR // IR
#define IR_SUPPORT 1 #define IR_SUPPORT 1
#define IR_PIN 4
#define IR_RECEIVER_PIN 4
#define IR_BUTTON_SET 1 #define IR_BUTTON_SET 1
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -2109,7 +2129,7 @@
#define BUTTON1_PIN 12 #define BUTTON1_PIN 12
#define BUTTON1_RELAY 1 #define BUTTON1_RELAY 1
#define BUTTON1_MODE BUTTON_SWITCH | BUTTON_DEFAULT_HIGH //Hardware Pullup #define BUTTON1_MODE BUTTON_SWITCH | BUTTON_DEFAULT_HIGH //Hardware Pullup
#define BUTTON1_PRESS BUTTON_MODE_NONE #define BUTTON1_PRESS BUTTON_MODE_NONE
#define BUTTON1_CLICK BUTTON_MODE_TOGGLE #define BUTTON1_CLICK BUTTON_MODE_TOGGLE
#define BUTTON1_DBLCLICK BUTTON_MODE_NONE #define BUTTON1_DBLCLICK BUTTON_MODE_NONE
@ -2318,6 +2338,60 @@
#define HLW8012_POWER_RATIO 3414290 #define HLW8012_POWER_RATIO 3414290
#define HLW8012_INTERRUPT_ON FALLING #define HLW8012_INTERRUPT_ON FALLING
// ----------------------------------------------------------------------------------------
// Homecube 16A is similar but some pins differ and it also has RGB LEDs
// https://www.amazon.de/gp/product/B07D7RVF56/ref=oh_aui_detailpage_o00_s01?ie=UTF8&psc=1
// ----------------------------------------------------------------------------------------
#elif defined(HOMECUBE_16A)
// Info
#define MANUFACTURER "HOMECUBE"
#define DEVICE "16A"
// Buttons
#define BUTTON1_PIN 13
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1
// Relays
#define RELAY1_PIN 15
#define RELAY1_TYPE RELAY_TYPE_NORMAL
// LEDs
//LED Pin 4 - ESP8266 onboard LED
//Red LED: 0
//Green LED: 12
//Blue LED: 2
// Blue
#define LED1_PIN 2
#define LED1_PIN_INVERSE 0
// Green
#define LED2_PIN 12
#define LED2_PIN_INVERSE 1
#define LED2_MODE LED_MODE_RELAY
// Red
#define LED3_PIN 0
#define LED3_PIN_INVERSE 0
#define LED2_MODE LED_MODE_OFF
// HJL01 / BL0937
#ifndef HLW8012_SUPPORT
#define HLW8012_SUPPORT 1
#endif
#define HLW8012_SEL_PIN 16
#define HLW8012_CF1_PIN 14
#define HLW8012_CF_PIN 5
#define HLW8012_SEL_CURRENT LOW
#define HLW8012_CURRENT_RATIO 25740
#define HLW8012_VOLTAGE_RATIO 313400
#define HLW8012_POWER_RATIO 3414290
#define HLW8012_INTERRUPT_ON FALLING
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// VANZAVANZU Smart Outlet Socket (based on BL0937 or HJL-01) // VANZAVANZU Smart Outlet Socket (based on BL0937 or HJL-01)
// https://www.amazon.com/Smart-Plug-Wifi-Mini-VANZAVANZU/dp/B078PHD6S5 // https://www.amazon.com/Smart-Plug-Wifi-Mini-VANZAVANZU/dp/B078PHD6S5
@ -2506,6 +2580,11 @@
#define MANUFACTURER "TravisCI" #define MANUFACTURER "TravisCI"
#define DEVICE "Virtual board 02" #define DEVICE "Virtual board 02"
// Some buttons - pin 0
#define BUTTON1_PIN 0
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1
// A bit of CSE7766 - pin 1 // A bit of CSE7766 - pin 1
#ifndef CSE7766_SUPPORT #ifndef CSE7766_SUPPORT
#define CSE7766_SUPPORT 1 #define CSE7766_SUPPORT 1
@ -2521,7 +2600,7 @@
// IR - pin 4 // IR - pin 4
#define IR_SUPPORT 1 #define IR_SUPPORT 1
#define IR_PIN 4
#define IR_RECEIVER_PIN 4
#define IR_BUTTON_SET 1 #define IR_BUTTON_SET 1
// A bit of DHT - pin 5 // A bit of DHT - pin 5
@ -2537,10 +2616,10 @@
#define EVENTS_SUPPORT 1 #define EVENTS_SUPPORT 1
#define EVENTS_PIN 6 #define EVENTS_PIN 6
// HC-RS04
#define HCSR04_SUPPORT 1
#define HCSR04_TRIGGER 7
#define HCSR04_ECHO 8
// Sonar
#define SONAR_SUPPORT 1
#define SONAR_TRIGGER 7
#define SONAR_ECHO 8
// MHZ19 // MHZ19
#define MHZ19_SUPPORT 1 #define MHZ19_SUPPORT 1
@ -2573,6 +2652,11 @@
#define MANUFACTURER "TravisCI" #define MANUFACTURER "TravisCI"
#define DEVICE "Virtual board 03" #define DEVICE "Virtual board 03"
// Some buttons - pin 0
#define BUTTON1_PIN 0
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1
// MY9231 Light - pins 1,2 // MY9231 Light - pins 1,2
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT #define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX #define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX


+ 19
- 12
code/espurna/config/progmem.h View File

@ -58,6 +58,9 @@ PROGMEM const char espurna_modules[] =
#if INFLUXDB_SUPPORT #if INFLUXDB_SUPPORT
"INFLUXDB " "INFLUXDB "
#endif #endif
#if IR_SUPPORT
"IR "
#endif
#if LLMNR_SUPPORT #if LLMNR_SUPPORT
"LLMNR " "LLMNR "
#endif #endif
@ -166,8 +169,8 @@ PROGMEM const char espurna_sensors[] =
#if GUVAS12SD_SUPPORT #if GUVAS12SD_SUPPORT
"GUVAS12SD " "GUVAS12SD "
#endif #endif
#if HCSR04_SUPPORT
"HCSR04 "
#if SONAR_SUPPORT
"SONAR "
#endif #endif
#if HLW8012_SUPPORT #if HLW8012_SUPPORT
"HLW8012 " "HLW8012 "
@ -204,12 +207,13 @@ PROGMEM const char espurna_sensors[] =
PROGMEM const unsigned char magnitude_decimals[] = { PROGMEM const unsigned char magnitude_decimals[] = {
0, 0,
1, 0, 2,
3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 3, 3,
4, 4 // Geiger Counter decimals
1, 0, 2, // THP
3, 0, 0, 0, 0, 0, 0, 0, // Power decimals
0, 0, 0, // analog, digital, event
0, 0, 0, // PM
0, 0, 3, 3, 0,
4, 4, // Geiger Counter decimals
0
}; };
PROGMEM const char magnitude_unknown_topic[] = "unknown"; PROGMEM const char magnitude_unknown_topic[] = "unknown";
@ -226,7 +230,7 @@ PROGMEM const char magnitude_energy_topic[] = "energy";
PROGMEM const char magnitude_energy_delta_topic[] = "energy_delta"; PROGMEM const char magnitude_energy_delta_topic[] = "energy_delta";
PROGMEM const char magnitude_analog_topic[] = "analog"; PROGMEM const char magnitude_analog_topic[] = "analog";
PROGMEM const char magnitude_digital_topic[] = "digital"; PROGMEM const char magnitude_digital_topic[] = "digital";
PROGMEM const char magnitude_events_topic[] = "events";
PROGMEM const char magnitude_event_topic[] = "event";
PROGMEM const char magnitude_pm1dot0_topic[] = "pm1dot0"; PROGMEM const char magnitude_pm1dot0_topic[] = "pm1dot0";
PROGMEM const char magnitude_pm2dot5_topic[] = "pm2dot5"; PROGMEM const char magnitude_pm2dot5_topic[] = "pm2dot5";
PROGMEM const char magnitude_pm10_topic[] = "pm10"; PROGMEM const char magnitude_pm10_topic[] = "pm10";
@ -237,17 +241,19 @@ PROGMEM const char magnitude_distance_topic[] = "distance";
PROGMEM const char magnitude_hcho_topic[] = "hcho"; PROGMEM const char magnitude_hcho_topic[] = "hcho";
PROGMEM const char magnitude_geiger_cpm_topic[] = "ldr_cpm"; // local dose rate [Counts per minute] PROGMEM const char magnitude_geiger_cpm_topic[] = "ldr_cpm"; // local dose rate [Counts per minute]
PROGMEM const char magnitude_geiger_sv_topic[] = "ldr_uSvh"; // local dose rate [µSievert per hour] PROGMEM const char magnitude_geiger_sv_topic[] = "ldr_uSvh"; // local dose rate [µSievert per hour]
PROGMEM const char magnitude_count_topic[] = "count";
PROGMEM const char* const magnitude_topics[] = { PROGMEM const char* const magnitude_topics[] = {
magnitude_unknown_topic, magnitude_temperature_topic, magnitude_humidity_topic, magnitude_unknown_topic, magnitude_temperature_topic, magnitude_humidity_topic,
magnitude_pressure_topic, magnitude_current_topic, magnitude_voltage_topic, magnitude_pressure_topic, magnitude_current_topic, magnitude_voltage_topic,
magnitude_active_power_topic, magnitude_apparent_power_topic, magnitude_reactive_power_topic, magnitude_active_power_topic, magnitude_apparent_power_topic, magnitude_reactive_power_topic,
magnitude_power_factor_topic, magnitude_energy_topic, magnitude_energy_delta_topic, magnitude_power_factor_topic, magnitude_energy_topic, magnitude_energy_delta_topic,
magnitude_analog_topic, magnitude_digital_topic, magnitude_events_topic,
magnitude_analog_topic, magnitude_digital_topic, magnitude_event_topic,
magnitude_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic, magnitude_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic,
magnitude_co2_topic, magnitude_lux_topic, magnitude_uv_topic, magnitude_co2_topic, magnitude_lux_topic, magnitude_uv_topic,
magnitude_distance_topic, magnitude_hcho_topic, magnitude_distance_topic, magnitude_hcho_topic,
magnitude_geiger_cpm_topic, magnitude_geiger_sv_topic // Geiger Counter topics
magnitude_geiger_cpm_topic, magnitude_geiger_sv_topic,
magnitude_count_topic
}; };
PROGMEM const char magnitude_empty[] = ""; PROGMEM const char magnitude_empty[] = "";
@ -280,7 +286,8 @@ PROGMEM const char* const magnitude_units[] = {
magnitude_ugm3, magnitude_ugm3, magnitude_ugm3, magnitude_ugm3, magnitude_ugm3, magnitude_ugm3,
magnitude_ppm, magnitude_lux, magnitude_uv, magnitude_ppm, magnitude_lux, magnitude_uv,
magnitude_distance, magnitude_mgm3, magnitude_distance, magnitude_mgm3,
magnitude_geiger_cpm, magnitude_geiger_sv // Geiger counter units
magnitude_geiger_cpm, magnitude_geiger_sv, // Geiger counter units
magnitude_empty
}; };
#endif #endif

+ 2
- 0
code/espurna/config/prototypes.h View File

@ -144,6 +144,8 @@ void nice_delay(unsigned long ms);
#define AsyncWebSocket void #define AsyncWebSocket void
#define AwsEventType void * #define AwsEventType void *
#endif #endif
typedef std::function<bool(AsyncWebServerRequest *request)> web_request_callback_f;
void webRequestRegister(web_request_callback_f callback);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// WebSockets // WebSockets


+ 44
- 24
code/espurna/config/sensors.h View File

@ -281,6 +281,11 @@
#define EVENTS_SUPPORT 0 // Do not build with counter support by default #define EVENTS_SUPPORT 0 // Do not build with counter support by default
#endif #endif
#ifndef EVENTS_TRIGGER
#define EVENTS_TRIGGER 1 // 1 to trigger callback on events,
// 0 to only count them and report periodically
#endif
#ifndef EVENTS_PIN #ifndef EVENTS_PIN
#define EVENTS_PIN 2 // GPIO to monitor #define EVENTS_PIN 2 // GPIO to monitor
#endif #endif
@ -337,23 +342,6 @@
#define GUVAS12SD_PIN 14 #define GUVAS12SD_PIN 14
#endif #endif
//------------------------------------------------------------------------------
// HC-SR04
// Enable support by passing HCSR04_SUPPORT=1 build flag
//------------------------------------------------------------------------------
#ifndef HCSR04_SUPPORT
#define HCSR04_SUPPORT 0
#endif
#ifndef HCSR04_TRIGGER
#define HCSR04_TRIGGER 12 // GPIO for the trigger pin (output)
#endif
#ifndef HCSR04_ECHO
#define HCSR04_ECHO 14 // GPIO for the echo pin (input)
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// HLW8012 Energy monitor IC // HLW8012 Energy monitor IC
// Enable support by passing HLW8012_SUPPORT=1 build flag // Enable support by passing HLW8012_SUPPORT=1 build flag
@ -504,14 +492,21 @@
#define PMS_SMART_SLEEP 0 #define PMS_SMART_SLEEP 0
#endif #endif
#ifndef PMS_USE_SOFT
#define PMS_USE_SOFT 0 // If PMS_USE_SOFT == 1, DEBUG_SERIAL_SUPPORT must be 0
#endif
#ifndef PMS_RX_PIN #ifndef PMS_RX_PIN
#define PMS_RX_PIN 13
#define PMS_RX_PIN 13 // Software serial RX GPIO (if PMS_USE_SOFT == 1)
#endif #endif
#ifndef PMS_TX_PIN #ifndef PMS_TX_PIN
#define PMS_TX_PIN 15
#define PMS_TX_PIN 15 // Software serial TX GPIO (if PMS_USE_SOFT == 1)
#endif #endif
#ifndef PMS_HW_PORT
#define PMS_HW_PORT Serial // Hardware serial port (if PMS_USE_SOFT == 0)
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// PZEM004T based power monitor // PZEM004T based power monitor
// Enable support by passing PZEM004T_SUPPORT=1 build flag // Enable support by passing PZEM004T_SUPPORT=1 build flag
@ -563,6 +558,31 @@
#define SI7021_ADDRESS 0x00 // 0x00 means auto #define SI7021_ADDRESS 0x00 // 0x00 means auto
#endif #endif
//------------------------------------------------------------------------------
// Sonar
// Enable support by passing SONAR_SUPPORT=1 build flag
//------------------------------------------------------------------------------
#ifndef SONAR_SUPPORT
#define SONAR_SUPPORT 0
#endif
#ifndef SONAR_TRIGGER
#define SONAR_TRIGGER 12 // GPIO for the trigger pin (output)
#endif
#ifndef SONAR_ECHO
#define SONAR_ECHO 14 // GPIO for the echo pin (input)
#endif
#ifndef SONAR_MAX_DISTANCE
#define SONAR_MAX_DISTANCE MAX_SENSOR_DISTANCE // Max sensor distance in cm
#endif
#ifndef SONAR_ITERATIONS
#define SONAR_ITERATIONS 5 // Number of iterations to ping for
#endif // error correction.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// TMP3X analog temperature sensor // TMP3X analog temperature sensor
// Enable support by passing TMP3X_SUPPORT=1 build flag // Enable support by passing TMP3X_SUPPORT=1 build flag
@ -623,7 +643,6 @@
EVENTS_SUPPORT || \ EVENTS_SUPPORT || \
GEIGER_SUPPORT || \ GEIGER_SUPPORT || \
GUVAS12SD_SUPPORT || \ GUVAS12SD_SUPPORT || \
HCSR04_SUPPORT || \
HLW8012_SUPPORT || \ HLW8012_SUPPORT || \
MHZ19_SUPPORT || \ MHZ19_SUPPORT || \
NTC_SUPPORT || \ NTC_SUPPORT || \
@ -632,6 +651,7 @@
PZEM004T_SUPPORT || \ PZEM004T_SUPPORT || \
SHT3X_I2C_SUPPORT || \ SHT3X_I2C_SUPPORT || \
SI7021_SUPPORT || \ SI7021_SUPPORT || \
SONAR_SUPPORT || \
TMP3X_SUPPORT || \ TMP3X_SUPPORT || \
V9261F_SUPPORT \ V9261F_SUPPORT \
) )
@ -743,10 +763,6 @@
#include "../sensors/GUVAS12SDSensor.h" #include "../sensors/GUVAS12SDSensor.h"
#endif #endif
#if HCSR04_SUPPORT
#include "../sensors/HCSR04Sensor.h"
#endif
#if HLW8012_SUPPORT #if HLW8012_SUPPORT
#include <HLW8012.h> #include <HLW8012.h>
#include "../sensors/HLW8012Sensor.h" #include "../sensors/HLW8012Sensor.h"
@ -785,6 +801,10 @@
#include "../sensors/SHT3XI2CSensor.h" #include "../sensors/SHT3XI2CSensor.h"
#endif #endif
#if SONAR_SUPPORT
#include "../sensors/SonarSensor.h"
#endif
#if TMP3X_SUPPORT #if TMP3X_SUPPORT
#include "../sensors/TMP3XSensor.h" #include "../sensors/TMP3XSensor.h"
#endif #endif


+ 32
- 33
code/espurna/config/types.h View File

@ -84,36 +84,36 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Priority codes: // Priority codes:
#define SYSLOG_EMERG 0 /* system is unusable */
#define SYSLOG_ALERT 1 /* action must be taken immediately */
#define SYSLOG_CRIT 2 /* critical conditions */
#define SYSLOG_ERR 3 /* error conditions */
#define SYSLOG_WARNING 4 /* warning conditions */
#define SYSLOG_NOTICE 5 /* normal but significant condition */
#define SYSLOG_INFO 6 /* informational */
#define SYSLOG_DEBUG 7 /* debug-level messages */
#define SYSLOG_EMERG 0 /* system is unusable */
#define SYSLOG_ALERT 1 /* action must be taken immediately */
#define SYSLOG_CRIT 2 /* critical conditions */
#define SYSLOG_ERR 3 /* error conditions */
#define SYSLOG_WARNING 4 /* warning conditions */
#define SYSLOG_NOTICE 5 /* normal but significant condition */
#define SYSLOG_INFO 6 /* informational */
#define SYSLOG_DEBUG 7 /* debug-level messages */
// Facility codes: // Facility codes:
#define SYSLOG_KERN (0<<3) /* kernel messages */
#define SYSLOG_USER (1<<3) /* random user-level messages */
#define SYSLOG_MAIL (2<<3) /* mail system */
#define SYSLOG_DAEMON (3<<3) /* system daemons */
#define SYSLOG_AUTH (4<<3) /* security/authorization messages */
#define SYSLOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
#define SYSLOG_LPR (6<<3) /* line printer subsystem */
#define SYSLOG_NEWS (7<<3) /* network news subsystem */
#define SYSLOG_UUCP (8<<3) /* UUCP subsystem */
#define SYSLOG_CRON (9<<3) /* clock daemon */
#define SYSLOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
#define SYSLOG_FTP (11<<3) /* ftp daemon */
#define SYSLOG_LOCAL0 (16<<3) /* reserved for local use */
#define SYSLOG_LOCAL1 (17<<3) /* reserved for local use */
#define SYSLOG_LOCAL2 (18<<3) /* reserved for local use */
#define SYSLOG_LOCAL3 (19<<3) /* reserved for local use */
#define SYSLOG_LOCAL4 (20<<3) /* reserved for local use */
#define SYSLOG_LOCAL5 (21<<3) /* reserved for local use */
#define SYSLOG_LOCAL6 (22<<3) /* reserved for local use */
#define SYSLOG_LOCAL7 (23<<3) /* reserved for local use */
#define SYSLOG_KERN (0<<3) /* kernel messages */
#define SYSLOG_USER (1<<3) /* random user-level messages */
#define SYSLOG_MAIL (2<<3) /* mail system */
#define SYSLOG_DAEMON (3<<3) /* system daemons */
#define SYSLOG_AUTH (4<<3) /* security/authorization messages */
#define SYSLOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
#define SYSLOG_LPR (6<<3) /* line printer subsystem */
#define SYSLOG_NEWS (7<<3) /* network news subsystem */
#define SYSLOG_UUCP (8<<3) /* UUCP subsystem */
#define SYSLOG_CRON (9<<3) /* clock daemon */
#define SYSLOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
#define SYSLOG_FTP (11<<3) /* ftp daemon */
#define SYSLOG_LOCAL0 (16<<3) /* reserved for local use */
#define SYSLOG_LOCAL1 (17<<3) /* reserved for local use */
#define SYSLOG_LOCAL2 (18<<3) /* reserved for local use */
#define SYSLOG_LOCAL3 (19<<3) /* reserved for local use */
#define SYSLOG_LOCAL4 (20<<3) /* reserved for local use */
#define SYSLOG_LOCAL5 (21<<3) /* reserved for local use */
#define SYSLOG_LOCAL6 (22<<3) /* reserved for local use */
#define SYSLOG_LOCAL7 (23<<3) /* reserved for local use */
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// MQTT // MQTT
@ -267,7 +267,7 @@
#define SENSOR_GUVAS12SD_ID 0x20 #define SENSOR_GUVAS12SD_ID 0x20
#define SENSOR_CSE7766_ID 0x21 #define SENSOR_CSE7766_ID 0x21
#define SENSOR_TMP3X_ID 0x22 #define SENSOR_TMP3X_ID 0x22
#define SENSOR_HCSR04_ID 0x23
#define SENSOR_SONAR_ID 0x23
#define SENSOR_SENSEAIR_ID 0x24 #define SENSOR_SENSEAIR_ID 0x24
#define SENSOR_GEIGER_ID 0x25 #define SENSOR_GEIGER_ID 0x25
#define SENSOR_NTC_ID 0x26 #define SENSOR_NTC_ID 0x26
@ -290,7 +290,7 @@
#define MAGNITUDE_ENERGY_DELTA 11 #define MAGNITUDE_ENERGY_DELTA 11
#define MAGNITUDE_ANALOG 12 #define MAGNITUDE_ANALOG 12
#define MAGNITUDE_DIGITAL 13 #define MAGNITUDE_DIGITAL 13
#define MAGNITUDE_EVENTS 14
#define MAGNITUDE_EVENT 14
#define MAGNITUDE_PM1dot0 15 #define MAGNITUDE_PM1dot0 15
#define MAGNITUDE_PM2dot5 16 #define MAGNITUDE_PM2dot5 16
#define MAGNITUDE_PM10 17 #define MAGNITUDE_PM10 17
@ -301,14 +301,13 @@
#define MAGNITUDE_HCHO 22 #define MAGNITUDE_HCHO 22
#define MAGNITUDE_GEIGER_CPM 23 #define MAGNITUDE_GEIGER_CPM 23
#define MAGNITUDE_GEIGER_SIEVERT 24 #define MAGNITUDE_GEIGER_SIEVERT 24
#define MAGNITUDE_COUNT 25
#define MAGNITUDE_MAX 25
#define MAGNITUDE_MAX 26
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// GPIO // GPIO
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
#define GPIO_NONE 0xFF
#define GPIO_LOGIC_DIRECT 0 #define GPIO_LOGIC_DIRECT 0
#define GPIO_LOGIC_INVERSE 1 #define GPIO_LOGIC_INVERSE 1

+ 1
- 1
code/espurna/config/version.h View File

@ -1,5 +1,5 @@
#define APP_NAME "ESPURNA" #define APP_NAME "ESPURNA"
#define APP_VERSION "1.13.2a"
#define APP_VERSION "1.13.2c"
#define APP_AUTHOR "xose.perez@gmail.com" #define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat" #define APP_WEBSITE "http://tinkerman.cat"
#define CFG_VERSION 4 #define CFG_VERSION 4

BIN
code/espurna/data/index.all.html.gz View File


BIN
code/espurna/data/index.sensor.html.gz View File


+ 1
- 1
code/espurna/eeprom.ino View File

@ -12,7 +12,7 @@ Module key prefix: eep
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool eepromRotate(bool value) {
void eepromRotate(bool value) {
// Enable/disable EEPROM rotation only if we are using more sectors than the // Enable/disable EEPROM rotation only if we are using more sectors than the
// reserved by the memory layout // reserved by the memory layout
if (EEPROMr.size() > EEPROMr.reserved()) { if (EEPROMr.size() > EEPROMr.reserved()) {


+ 1
- 1
code/espurna/hardware.ino View File

@ -1876,7 +1876,7 @@ void _hardwareSpecific() {
// These devices use the hardware UART // These devices use the hardware UART
// to communicate to secondary microcontrollers // to communicate to secondary microcontrollers
#if defined(ITEAD_SONOFF_RFBRIDGE) || defined(ITEAD_SONOFF_DUAL) || defined(STM_RELAY)
#if defined(ITEAD_SONOFF_RFBRIDGE) || defined(ITEAD_SONOFF_DUAL) || (RELAY_PROVIDER == RELAY_PROVIDER_STM)
Serial.begin(DEBUG_SERIAL_SPEED); Serial.begin(DEBUG_SERIAL_SPEED);
#endif #endif


+ 4
- 4
code/espurna/homeassistant.ino View File

@ -75,11 +75,11 @@ void _haSendSwitch(unsigned char i, JsonObject& config) {
if (relayCount()) { if (relayCount()) {
config["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false); config["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false);
config["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, true); config["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, true);
config["payload_on"] = String("1");
config["payload_off"] = String("0");
config["payload_on"] = String(HOMEASSISTANT_PAYLOAD_ON);
config["payload_off"] = String(HOMEASSISTANT_PAYLOAD_OFF);
config["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false); config["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false);
config["payload_available"] = String("1");
config["payload_not_available"] = String("0");
config["payload_available"] = String(HOMEASSISTANT_PAYLOAD_ON);
config["payload_not_available"] = String(HOMEASSISTANT_PAYLOAD_OFF);
} }
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE


+ 2
- 2
code/espurna/i2c.ino View File

@ -236,7 +236,7 @@ uint16_t i2c_read_uint16(uint8_t address, uint8_t reg) {
void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len) { void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len) {
Wire.beginTransmission((uint8_t) address); Wire.beginTransmission((uint8_t) address);
Wire.requestFrom(address, (uint8_t) len); Wire.requestFrom(address, (uint8_t) len);
for (int i=0; i<len; i++) buffer[i] = Wire.read();
for (size_t i=0; i<len; i++) buffer[i] = Wire.read();
Wire.endTransmission(); Wire.endTransmission();
} }
@ -338,7 +338,7 @@ unsigned char i2cFind(size_t size, unsigned char * addresses) {
unsigned char i2cFindAndLock(size_t size, unsigned char * addresses) { unsigned char i2cFindAndLock(size_t size, unsigned char * addresses) {
unsigned char start = 0; unsigned char start = 0;
unsigned char address = 0; unsigned char address = 0;
while (address = i2cFind(size, addresses, start)) {
while ((address = i2cFind(size, addresses, start))) {
if (i2cGetLock(address)) break; if (i2cGetLock(address)) break;
start++; start++;
} }


+ 58
- 55
code/espurna/ir.ino View File

@ -22,80 +22,84 @@ unsigned long _ir_last_toggle = 0;
// PRIVATE // PRIVATE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void _irProcessCode(unsigned long code) {
void _irProcessCode(unsigned long code, unsigned char type) {
static unsigned long last_code;
boolean found = false;
// Check valid code
unsigned long last_code = 0;
unsigned long last_time = 0;
if (code == 0xFFFFFFFF) return;
if (type == 0xFF) return;
if ((last_code == code) && (millis() - last_time < IR_DEBOUNCE)) return;
last_code = code;
DEBUG_MSG_P(PSTR("[IR] Received 0x%08X (%d)\n"), code, type);
// Repeat last valid code
DEBUG_MSG_P(PSTR("[IR] Received 0x%06X\n"), code);
if (code == 0xFFFFFFFF) {
DEBUG_MSG_P(PSTR("[IR] Processing 0x%06X\n"), code);
code = last_code;
}
#if IR_BUTTON_SET > 0
for (unsigned char i = 0; i < IR_BUTTON_COUNT ; i++) {
boolean found = false;
unsigned long button_code = pgm_read_dword(&IR_BUTTON[i][0]);
if (code == button_code) {
for (unsigned char i = 0; i < IR_BUTTON_COUNT ; i++) {
unsigned long button_mode = pgm_read_dword(&IR_BUTTON[i][1]);
unsigned long button_value = pgm_read_dword(&IR_BUTTON[i][2]);
uint32_t button_code = pgm_read_dword(&IR_BUTTON[i][0]);
if (code == button_code) {
if (button_mode == IR_BUTTON_MODE_STATE) {
relayStatus(0, button_value);
}
unsigned long button_mode = pgm_read_dword(&IR_BUTTON[i][1]);
unsigned long button_value = pgm_read_dword(&IR_BUTTON[i][2]);
if (button_mode == IR_BUTTON_MODE_TOGGLE) {
if (button_mode == IR_BUTTON_MODE_STATE) {
relayStatus(0, button_value);
}
if (millis() - _ir_last_toggle > 250){
if (button_mode == IR_BUTTON_MODE_TOGGLE) {
relayToggle(button_value); relayToggle(button_value);
_ir_last_toggle = millis();
} else {
DEBUG_MSG_P(PSTR("[IR] Ignoring repeated code\n"));
} }
}
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
if (button_mode == IR_BUTTON_MODE_BRIGHTER) {
lightBrightnessStep(button_value ? 1 : -1);
nice_delay(150); //debounce
}
if (button_mode == IR_BUTTON_MODE_BRIGHTER) {
lightBrightnessStep(button_value ? 1 : -1);
nice_delay(150); //debounce
}
if (button_mode == IR_BUTTON_MODE_RGB) {
lightColor(button_value);
}
if (button_mode == IR_BUTTON_MODE_RGB) {
lightColor(button_value);
}
/*
#if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
if (button_mode == IR_BUTTON_MODE_EFFECT) {
_buttonAnimMode(button_value);
/*
#if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
if (button_mode == IR_BUTTON_MODE_EFFECT) {
_buttonAnimMode(button_value);
}
#endif
*/
/*
if (button_mode == IR_BUTTON_MODE_HSV) {
lightColor(button_value);
} }
#endif
*/
*/
/*
if (button_mode == IR_BUTTON_MODE_HSV) {
lightColor(button_value);
}
*/
lightUpdate(true, true);
lightUpdate(true, true);
#endif
#endif
found = true;
break;
found = true;
last_code = code;
break;
}
}
}
}
if (!found) {
DEBUG_MSG_P(PSTR("[IR] Ignoring code\n"));
}
if (!found) {
DEBUG_MSG_P(PSTR("[IR] Ignoring code\n"));
}
#endif
#if MQTT_SUPPORT
char buffer[16];
snprintf_P(buffer, sizeof(buffer), "0x%08X", code);
mqttSend(MQTT_TOPIC_IR, buffer);
#endif
} }
@ -109,7 +113,7 @@ bool _irKeyCheck(const char * key) {
void irSetup() { void irSetup() {
_ir_recv = new IRrecv(IR_PIN);
_ir_recv = new IRrecv(IR_RECEIVER_PIN);
_ir_recv->enableIRIn(); _ir_recv->enableIRIn();
// Key Check // Key Check
@ -122,8 +126,7 @@ void irSetup() {
void irLoop() { void irLoop() {
if (_ir_recv->decode(&_ir_results)) { if (_ir_recv->decode(&_ir_results)) {
unsigned long code = _ir_results.value;
_irProcessCode(code);
_irProcessCode(_ir_results.value, _ir_results.decode_type);
_ir_recv->resume(); // Receive the next value _ir_recv->resume(); // Receive the next value
} }
} }


+ 1
- 1
code/espurna/led.ino View File

@ -304,4 +304,4 @@ void ledSetup() {
} }
#endif LED_SUPPORT
#endif // LED_SUPPORT

+ 8
- 2
code/espurna/ota.ino View File

@ -246,8 +246,14 @@ void otaSetup() {
deferredReset(100, CUSTOM_RESET_OTA); deferredReset(100, CUSTOM_RESET_OTA);
}); });
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
DEBUG_MSG_P(PSTR("[OTA] Progress: %u%%\r"), (progress / (total / 100)));
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
static unsigned int _progOld;
unsigned int _prog = (progress / (total / 100));
if (_prog != _progOld) {
DEBUG_MSG_P(PSTR("[OTA] Progress: %u%%\r"), _prog);
_progOld = _prog;
}
}); });
ArduinoOTA.onError([](ota_error_t error) { ArduinoOTA.onError([](ota_error_t error) {


+ 9
- 10
code/espurna/relay.ino View File

@ -101,7 +101,7 @@ void _relayProviderStatus(unsigned char id, bool status) {
if (_relays.size() == lightChannels()) { if (_relays.size() == lightChannels()) {
lightState(id, status); lightState(id, status);
lightState(true); lightState(true);
} else if (_relays.size() == lightChannels() + 1) {
} else if (_relays.size() == (lightChannels() + 1u)) {
if (id == 0) { if (id == 0) {
lightState(status); lightState(status);
} else { } else {
@ -561,6 +561,8 @@ void _relayConfigure() {
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
unsigned char type = getSetting("rlyType", index, RELAY_TYPE_NORMAL).toInt(); unsigned char type = getSetting("rlyType", index, RELAY_TYPE_NORMAL).toInt();
if (RELAY_TYPE_INVERSE == type) digitalWrite(pin, HIGH);
unsigned char reset = getSetting("rlyResetGPIO", index, GPIO_NONE).toInt(); unsigned char reset = getSetting("rlyResetGPIO", index, GPIO_NONE).toInt();
if (GPIO_NONE != reset) pinMode(reset, OUTPUT); if (GPIO_NONE != reset) pinMode(reset, OUTPUT);
@ -568,7 +570,7 @@ void _relayConfigure() {
unsigned long delay_off = getSetting("rlyDelayOff", index, 0).toInt(); unsigned long delay_off = getSetting("rlyDelayOff", index, 0).toInt();
unsigned char pulse = getSetting("rlyPulse", index, RELAY_PULSE_MODE).toInt(); unsigned char pulse = getSetting("rlyPulse", index, RELAY_PULSE_MODE).toInt();
float pulse_ms = 1000 * getSetting("rlyTime", index, RELAY_PULSE_TIME).toFloat();
unsigned long pulse_ms = 1000 * getSetting("rlyTime", index, RELAY_PULSE_TIME).toFloat();
_relays.push_back((relay_t) { pin, type, reset, delay_on, delay_off, pulse, pulse_ms }); _relays.push_back((relay_t) { pin, type, reset, delay_on, delay_off, pulse, pulse_ms });
++index; ++index;
@ -678,11 +680,11 @@ void relaySetupWS() {
void relaySetupAPI() { void relaySetupAPI() {
char key[20];
// API entry points (protected with apikey) // API entry points (protected with apikey)
for (unsigned int relayID=0; relayID<relayCount(); relayID++) { for (unsigned int relayID=0; relayID<relayCount(); relayID++) {
char key[20];
snprintf_P(key, sizeof(key), PSTR("%s/%d"), MQTT_TOPIC_RELAY, relayID); snprintf_P(key, sizeof(key), PSTR("%s/%d"), MQTT_TOPIC_RELAY, relayID);
apiRegister(key, apiRegister(key,
[relayID](char * buffer, size_t len) { [relayID](char * buffer, size_t len) {
@ -726,9 +728,6 @@ void relaySetupAPI() {
_relays[relayID].pulse = relayStatus(relayID) ? RELAY_PULSE_ON : RELAY_PULSE_OFF; _relays[relayID].pulse = relayStatus(relayID) ? RELAY_PULSE_ON : RELAY_PULSE_OFF;
relayToggle(relayID, true, false); relayToggle(relayID, true, false);
return;
} }
); );
@ -764,7 +763,7 @@ void relayMQTT(unsigned char id) {
// Send state topic // Send state topic
if (_relays[id].report) { if (_relays[id].report) {
_relays[id].report = false; _relays[id].report = false;
mqttSend(MQTT_TOPIC_RELAY, id, _relays[id].current_status ? "1" : "0");
mqttSend(MQTT_TOPIC_RELAY, id, _relays[id].current_status ? RELAY_MQTT_ON : RELAY_MQTT_OFF);
} }
// Check group topic // Check group topic
@ -774,7 +773,7 @@ void relayMQTT(unsigned char id) {
if (t.length() > 0) { if (t.length() > 0) {
bool status = relayStatus(id); bool status = relayStatus(id);
if (getSetting("mqttGroupInv", id, 0).toInt() == 1) status = !status; if (getSetting("mqttGroupInv", id, 0).toInt() == 1) status = !status;
mqttSendRaw(t.c_str(), status ? "1" : "0");
mqttSendRaw(t.c_str(), status ? RELAY_MQTT_ON : RELAY_MQTT_OFF);
} }
} }
@ -789,7 +788,7 @@ void relayMQTT(unsigned char id) {
void relayMQTT() { void relayMQTT() {
for (unsigned int id=0; id < _relays.size(); id++) { for (unsigned int id=0; id < _relays.size(); id++) {
mqttSend(MQTT_TOPIC_RELAY, id, _relays[id].current_status ? "1" : "0");
mqttSend(MQTT_TOPIC_RELAY, id, _relays[id].current_status ? RELAY_MQTT_ON : RELAY_MQTT_OFF);
} }
} }


+ 106
- 78
code/espurna/sensor.ino View File

@ -109,6 +109,8 @@ void _sensorWebSocketSendData(JsonObject& root) {
for (unsigned char i=0; i<_magnitudes.size(); i++) { for (unsigned char i=0; i<_magnitudes.size(); i++) {
sensor_magnitude_t magnitude = _magnitudes[i]; sensor_magnitude_t magnitude = _magnitudes[i];
if (magnitude.type == MAGNITUDE_EVENT) continue;
unsigned char decimals = _magnitudeDecimals(magnitude.type); unsigned char decimals = _magnitudeDecimals(magnitude.type);
dtostrf(magnitude.current, 1-sizeof(buffer), decimals, buffer); dtostrf(magnitude.current, 1-sizeof(buffer), decimals, buffer);
@ -440,7 +442,8 @@ void _sensorLoad() {
{ {
EventSensor * sensor = new EventSensor(); EventSensor * sensor = new EventSensor();
sensor->setGPIO(EVENTS_PIN); sensor->setGPIO(EVENTS_PIN);
sensor->setMode(EVENTS_PIN_MODE);
sensor->setTrigger(EVENTS_TRIGGER);
sensor->setPinMode(EVENTS_PIN_MODE);
sensor->setDebounceTime(EVENTS_DEBOUNCE); sensor->setDebounceTime(EVENTS_DEBOUNCE);
sensor->setInterruptMode(EVENTS_INTERRUPT_MODE); sensor->setInterruptMode(EVENTS_INTERRUPT_MODE);
_sensors.push_back(sensor); _sensors.push_back(sensor);
@ -467,11 +470,13 @@ void _sensorLoad() {
} }
#endif #endif
#if HCSR04_SUPPORT
#if SONAR_SUPPORT
{ {
HCSR04Sensor * sensor = new HCSR04Sensor();
sensor->setTrigger(HCSR04_TRIGGER);
sensor->setEcho(HCSR04_ECHO);
SonarSensor * sensor = new SonarSensor();
sensor->setEcho(SONAR_ECHO);
sensor->setIterations(SONAR_ITERATIONS);
sensor->setMaxDistance(SONAR_MAX_DISTANCE);
sensor->setTrigger(SONAR_TRIGGER);
_sensors.push_back(sensor); _sensors.push_back(sensor);
} }
#endif #endif
@ -522,8 +527,12 @@ void _sensorLoad() {
#if PMSX003_SUPPORT #if PMSX003_SUPPORT
{ {
PMSX003Sensor * sensor = new PMSX003Sensor(); PMSX003Sensor * sensor = new PMSX003Sensor();
sensor->setRX(PMS_RX_PIN);
sensor->setTX(PMS_TX_PIN);
#if PMS_USE_SOFT
sensor->setRX(PMS_RX_PIN);
sensor->setTX(PMS_TX_PIN);
#else
sensor->setSerial(& PMS_HW_PORT);
#endif
sensor->setType(PMS_TYPE); sensor->setType(PMS_TYPE);
_sensors.push_back(sensor); _sensors.push_back(sensor);
} }
@ -577,8 +586,17 @@ void _sensorLoad() {
} }
void _sensorCallback(unsigned char i, unsigned char type, const char * payload) {
DEBUG_MSG_P(PSTR("[SENSOR] Sensor #%u callback, type %u, payload: '%s'\n"), i, type, payload);
void _sensorCallback(unsigned char i, unsigned char type, double value) {
DEBUG_MSG_P(PSTR("[SENSOR] Sensor #%u callback, type %u, payload: '%s'\n"), i, type, String(value).c_str());
for (unsigned char k=0; k<_magnitudes.size(); k++) {
if ((_sensors[i] == _magnitudes[k].sensor) && (type == _magnitudes[k].type)) {
_sensorReport(k, value);
return;
}
}
} }
void _sensorInit() { void _sensorInit() {
@ -615,7 +633,7 @@ void _sensorInit() {
new_magnitude.min_change = 0; new_magnitude.min_change = 0;
if (type == MAGNITUDE_DIGITAL) { if (type == MAGNITUDE_DIGITAL) {
new_magnitude.filter = new MaxFilter(); new_magnitude.filter = new MaxFilter();
} else if (type == MAGNITUDE_EVENTS || type == MAGNITUDE_GEIGER_CPM|| type == MAGNITUDE_GEIGER_SIEVERT) { // For geiger counting moving average filter is the most appropriate if needed at all.
} else if (type == MAGNITUDE_COUNT || type == MAGNITUDE_GEIGER_CPM|| type == MAGNITUDE_GEIGER_SIEVERT) { // For geiger counting moving average filter is the most appropriate if needed at all.
new_magnitude.filter = new MovingAverageFilter(); new_magnitude.filter = new MovingAverageFilter();
} else { } else {
new_magnitude.filter = new MedianFilter(); new_magnitude.filter = new MedianFilter();
@ -630,8 +648,8 @@ void _sensorInit() {
} }
// Hook callback // Hook callback
_sensors[i]->onEvent([i](unsigned char type, const char * payload) {
_sensorCallback(i, type, payload);
_sensors[i]->onEvent([i](unsigned char type, double value) {
_sensorCallback(i, type, value);
}); });
// Custom initializations // Custom initializations
@ -714,7 +732,7 @@ void _sensorConfigure() {
double value; double value;
EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i]; EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i];
if (value = getSetting("pwrExpected", 0).toInt()) {
if ((value = getSetting("pwrExpected", 0).toInt())) {
sensor->expectedPower(0, value); sensor->expectedPower(0, value);
setSetting("curRatio", sensor->getCurrentRatio(0)); setSetting("curRatio", sensor->getCurrentRatio(0));
} }
@ -801,17 +819,17 @@ void _sensorConfigure() {
double value; double value;
CSE7766Sensor * sensor = (CSE7766Sensor *) _sensors[i]; CSE7766Sensor * sensor = (CSE7766Sensor *) _sensors[i];
if (value = getSetting("curExpected", 0).toFloat()) {
if ((value = getSetting("curExpected", 0).toFloat())) {
sensor->expectedCurrent(value); sensor->expectedCurrent(value);
setSetting("curRatio", sensor->getCurrentRatio()); setSetting("curRatio", sensor->getCurrentRatio());
} }
if (value = getSetting("volExpected", 0).toInt()) {
if ((value = getSetting("volExpected", 0).toInt())) {
sensor->expectedVoltage(value); sensor->expectedVoltage(value);
setSetting("volRatio", sensor->getVoltageRatio()); setSetting("volRatio", sensor->getVoltageRatio());
} }
if (value = getSetting("pwrExpected", 0).toInt()) {
if ((value = getSetting("pwrExpected", 0).toInt())) {
sensor->expectedPower(value); sensor->expectedPower(value);
setSetting("pwrRatio", sensor->getPowerRatio()); setSetting("pwrRatio", sensor->getPowerRatio());
} }
@ -887,6 +905,73 @@ void _sensorBackwards() {
moveSetting("pwrExpectedV", "volExpected"); // 1.14.0 - 2018-06-26 moveSetting("pwrExpectedV", "volExpected"); // 1.14.0 - 2018-06-26
moveSetting("pwrResetCalibration", "snsResetCalibration"); // 1.14.0 - 2018-06-26 moveSetting("pwrResetCalibration", "snsResetCalibration"); // 1.14.0 - 2018-06-26
moveSetting("pwrResetE", "eneReset"); // 1.14.0 - 2018-06-26 moveSetting("pwrResetE", "eneReset"); // 1.14.0 - 2018-06-26
}
void _sensorReport(unsigned char index, double value) {
sensor_magnitude_t magnitude = _magnitudes[index];
unsigned char decimals = _magnitudeDecimals(magnitude.type);
char buffer[10];
dtostrf(value, 1-sizeof(buffer), decimals, buffer);
#if BROKER_SUPPORT
brokerPublish(magnitudeTopic(magnitude.type).c_str(), magnitude.local, buffer);
#endif
#if MQTT_SUPPORT
mqttSend(magnitudeTopicIndex(index).c_str(), buffer);
#if SENSOR_PUBLISH_ADDRESSES
char topic[32];
snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, magnitudeTopic(magnitude.type).c_str());
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str());
} else {
mqttSend(topic, magnitude.sensor->address(magnitude.local).c_str());
}
#endif // SENSOR_PUBLISH_ADDRESSES
#endif // MQTT_SUPPORT
#if INFLUXDB_SUPPORT
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
idbSend(magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
} else {
idbSend(magnitudeTopic(magnitude.type).c_str(), buffer);
}
#endif // INFLUXDB_SUPPORT
#if THINGSPEAK_SUPPORT
tspkEnqueueMeasurement(index, buffer);
#endif
#if DOMOTICZ_SUPPORT
{
char key[15];
snprintf_P(key, sizeof(key), PSTR("dczMagnitude%d"), index);
if (magnitude.type == MAGNITUDE_HUMIDITY) {
int status;
if (value > 70) {
status = HUMIDITY_WET;
} else if (value > 45) {
status = HUMIDITY_COMFORTABLE;
} else if (value > 30) {
status = HUMIDITY_NORMAL;
} else {
status = HUMIDITY_DRY;
}
char status_buf[5];
itoa(status, status_buf, 10);
domoticzSend(key, buffer, status_buf);
} else {
domoticzSend(key, 0, buffer);
}
}
#endif // DOMOTICZ_SUPPORT
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -1026,7 +1111,6 @@ void sensorLoop() {
double current; double current;
double filtered; double filtered;
char buffer[64];
// Pre-read hook // Pre-read hook
_sensorPre(); _sensorPre();
@ -1062,19 +1146,18 @@ void sensorLoop() {
magnitude.filter->add(current); magnitude.filter->add(current);
// Special case // Special case
if (magnitude.type == MAGNITUDE_EVENTS) {
if (magnitude.type == MAGNITUDE_COUNT) {
current = magnitude.filter->result(); current = magnitude.filter->result();
} }
current = _magnitudeProcess(magnitude.type, current); current = _magnitudeProcess(magnitude.type, current);
_magnitudes[i].current = current; _magnitudes[i].current = current;
unsigned char decimals = _magnitudeDecimals(magnitude.type);
// Debug // Debug
#if SENSOR_DEBUG #if SENSOR_DEBUG
{ {
dtostrf(current, 1-sizeof(buffer), decimals, buffer);
char buffer[64];
dtostrf(current, 1-sizeof(buffer), _magnitudeDecimals(magnitude.type), buffer);
DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"), DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"),
magnitude.sensor->slot(magnitude.local).c_str(), magnitude.sensor->slot(magnitude.local).c_str(),
magnitudeTopic(magnitude.type).c_str(), magnitudeTopic(magnitude.type).c_str(),
@ -1096,63 +1179,8 @@ void sensorLoop() {
if (fabs(filtered - magnitude.reported) >= magnitude.min_change) { if (fabs(filtered - magnitude.reported) >= magnitude.min_change) {
_magnitudes[i].reported = filtered; _magnitudes[i].reported = filtered;
dtostrf(filtered, 1-sizeof(buffer), decimals, buffer);
#if BROKER_SUPPORT
brokerPublish(magnitudeTopic(magnitude.type).c_str(), magnitude.local, buffer);
#endif
#if MQTT_SUPPORT
mqttSend(magnitudeTopicIndex(i).c_str(), buffer);
#if SENSOR_PUBLISH_ADDRESSES
char topic[32];
snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, magnitudeTopic(magnitude.type).c_str());
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str());
} else {
mqttSend(topic, magnitude.sensor->address(magnitude.local).c_str());
}
#endif // SENSOR_PUBLISH_ADDRESSES
#endif // MQTT_SUPPORT
#if INFLUXDB_SUPPORT
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
idbSend(magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
} else {
idbSend(magnitudeTopic(magnitude.type).c_str(), buffer);
}
#endif // INFLUXDB_SUPPORT
#if THINGSPEAK_SUPPORT
tspkEnqueueMeasurement(i, buffer);
#endif
#if DOMOTICZ_SUPPORT
{
char key[15];
snprintf_P(key, sizeof(key), PSTR("dczMagnitude%d"), i);
if (magnitude.type == MAGNITUDE_HUMIDITY) {
int status;
if (filtered > 70) {
status = HUMIDITY_WET;
} else if (filtered > 45) {
status = HUMIDITY_COMFORTABLE;
} else if (filtered > 30) {
status = HUMIDITY_NORMAL;
} else {
status = HUMIDITY_DRY;
}
char status_buf[5];
itoa(status, status_buf, 10);
domoticzSend(key, buffer, status_buf);
} else {
domoticzSend(key, 0, buffer);
}
}
#endif // DOMOTICZ_SUPPORT
_sensorReport(i, filtered);
} // if (fabs(filtered - magnitude.reported) >= magnitude.min_change) } // if (fabs(filtered - magnitude.reported) >= magnitude.min_change)
} // if (report_count == 0) } // if (report_count == 0)


+ 6
- 6
code/espurna/sensors/BaseSensor.h View File

@ -21,7 +21,7 @@
#define SENSOR_ERROR_CALIBRATION 8 // Calibration error or Not calibrated #define SENSOR_ERROR_CALIBRATION 8 // Calibration error or Not calibrated
#define SENSOR_ERROR_OTHER 99 // Any other error #define SENSOR_ERROR_OTHER 99 // Any other error
typedef std::function<void(unsigned char, const char *)> TSensorCallback;
typedef std::function<void(unsigned char, double)> TSensorCallback;
class BaseSensor { class BaseSensor {
@ -46,19 +46,19 @@ class BaseSensor {
virtual void post() {} virtual void post() {}
// Descriptive name of the sensor // Descriptive name of the sensor
virtual String description() {}
virtual String description() = 0;
// Address of the sensor (it could be the GPIO or I2C address) // Address of the sensor (it could be the GPIO or I2C address)
virtual String address(unsigned char index) {}
virtual String address(unsigned char index) = 0;
// Descriptive name of the slot # index // Descriptive name of the slot # index
virtual String slot(unsigned char index) {};
virtual String slot(unsigned char index) = 0;
// Type for slot # index // Type for slot # index
virtual unsigned char type(unsigned char index) {}
virtual unsigned char type(unsigned char index) = 0;
// Current value for slot # index // Current value for slot # index
virtual double value(unsigned char index) {}
virtual double value(unsigned char index) = 0;
// Retrieve current instance configuration // Retrieve current instance configuration
virtual void getConfig(JsonObject& root) {}; virtual void getConfig(JsonObject& root) {};


+ 1
- 1
code/espurna/sensors/DHTSensor.h View File

@ -221,7 +221,7 @@ class DHTSensor : public BaseSensor {
} }
unsigned long _signal(int usTimeOut, bool state) {
unsigned long _signal(unsigned long usTimeOut, bool state) {
unsigned long uSec = 1; unsigned long uSec = 1;
while (digitalRead(_gpio) == state) { while (digitalRead(_gpio) == state) {
if (++uSec > usTimeOut) return 0; if (++uSec > usTimeOut) return 0;


+ 3
- 3
code/espurna/sensors/EmonSensor.h View File

@ -146,7 +146,7 @@ class EmonSensor : public I2CSensor {
#endif #endif
} }
virtual unsigned int readADC(unsigned char channel) {}
virtual unsigned int readADC(unsigned char channel) = 0;
void calculateFactors(unsigned char channel) { void calculateFactors(unsigned char channel) {
@ -154,8 +154,8 @@ class EmonSensor : public I2CSensor {
unsigned int s = 1; unsigned int s = 1;
unsigned int i = 1; unsigned int i = 1;
unsigned int m = s * i;
unsigned int multiplier;
unsigned int m = 1;
unsigned int multiplier = 1;
while (m * _current_factor[channel] < 1) { while (m * _current_factor[channel] < 1) {
multiplier = m; multiplier = m;
i = (i == 1) ? 2 : (i == 2) ? 5 : 1; i = (i == 1) ? 2 : (i == 2) ? 5 : 1;


+ 29
- 12
code/espurna/sensors/EventSensor.h View File

@ -33,12 +33,16 @@ class EventSensor : public BaseSensor {
_gpio = gpio; _gpio = gpio;
} }
void setMode(unsigned char mode) {
_mode = mode;
void setTrigger(bool trigger) {
_trigger = trigger;
} }
void setInterruptMode(unsigned char mode) {
_interrupt_mode = mode;
void setPinMode(unsigned char pin_mode) {
_pin_mode = pin_mode;
}
void setInterruptMode(unsigned char interrupt_mode) {
_interrupt_mode = interrupt_mode;
} }
void setDebounceTime(unsigned long debounce) { void setDebounceTime(unsigned long debounce) {
@ -51,8 +55,12 @@ class EventSensor : public BaseSensor {
return _gpio; return _gpio;
} }
unsigned char getMode() {
return _mode;
bool getTrigger() {
return _trigger;
}
unsigned char getPinMode() {
return _pin_mode;
} }
unsigned char getInterruptMode() { unsigned char getInterruptMode() {
@ -70,8 +78,9 @@ class EventSensor : public BaseSensor {
// Initialization method, must be idempotent // Initialization method, must be idempotent
// Defined outside the class body // Defined outside the class body
void begin() { void begin() {
pinMode(_gpio, _mode);
pinMode(_gpio, _pin_mode);
_enableInterrupts(true); _enableInterrupts(true);
_count = _trigger ? 2 : 1;
_ready = true; _ready = true;
} }
@ -94,7 +103,8 @@ class EventSensor : public BaseSensor {
// Type for slot # index // Type for slot # index
unsigned char type(unsigned char index) { unsigned char type(unsigned char index) {
if (index == 0) return MAGNITUDE_EVENTS;
if (index == 0) return MAGNITUDE_COUNT;
if (index == 1) return MAGNITUDE_EVENT;
return MAGNITUDE_NONE; return MAGNITUDE_NONE;
} }
@ -113,8 +123,14 @@ class EventSensor : public BaseSensor {
(void) gpio; (void) gpio;
static unsigned long last = 0; static unsigned long last = 0;
if (millis() - last > _debounce) { if (millis() - last > _debounce) {
_events = _events + 1;
last = millis(); last = millis();
_events = _events + 1;
if (_trigger) {
if (_callback) _callback(MAGNITUDE_EVENT, digitalRead(gpio));
}
} }
} }
@ -148,9 +164,10 @@ class EventSensor : public BaseSensor {
volatile unsigned long _events = 0; volatile unsigned long _events = 0;
unsigned long _debounce = EVENTS_DEBOUNCE; unsigned long _debounce = EVENTS_DEBOUNCE;
unsigned char _gpio;
unsigned char _mode;
unsigned char _interrupt_mode;
unsigned char _gpio = GPIO_NONE;
bool _trigger = false;
unsigned char _pin_mode = INPUT;
unsigned char _interrupt_mode = RISING;
}; };


+ 38
- 11
code/espurna/sensors/PMSX003Sensor.h View File

@ -12,7 +12,12 @@
#include "Arduino.h" #include "Arduino.h"
#include "BaseSensor.h" #include "BaseSensor.h"
#if PMS_USE_SOFT
#include <SoftwareSerial.h> #include <SoftwareSerial.h>
#endif
// Generic data
#define PMS_BAUD_RATE 9600
// Type of sensor // Type of sensor
#define PMS_TYPE_X003 0 #define PMS_TYPE_X003 0
@ -46,7 +51,7 @@ const static struct {
class PMSX003 { class PMSX003 {
protected: protected:
SoftwareSerial *_serial = NULL; // Should initialized by child class
Stream *_serial = NULL; // Should initialized by child class
public: public:
@ -175,7 +180,13 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
_dirty = true; _dirty = true;
} }
// Should call setType after constrcutor immediately to enable corresponding slot count
void setSerial(HardwareSerial * serial) {
_soft = false;
_serial = serial;
_dirty = true;
}
// Should call setType after constructor immediately to enable corresponding slot count
void setType(unsigned char type) { void setType(unsigned char type) {
_type = type; _type = type;
_count = pms_specs[_type].slot_count; _count = pms_specs[_type].slot_count;
@ -204,30 +215,45 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
if (!_dirty) return; if (!_dirty) return;
if (_serial) delete _serial;
if (_soft) {
if (_serial) delete _serial;
_serial = new SoftwareSerial(_pin_rx, _pin_tx, false, 64);
static_cast<SoftwareSerial*>(_serial)->enableIntTx(false);
}
if (_soft) {
static_cast<SoftwareSerial*>(_serial)->begin(PMS_BAUD_RATE);
} else {
static_cast<HardwareSerial*>(_serial)->begin(PMS_BAUD_RATE);
}
_serial = new SoftwareSerial(_pin_rx, _pin_tx, false, 64);
_serial->enableIntTx(false);
_serial->begin(9600);
passiveMode(); passiveMode();
_startTime = millis(); _startTime = millis();
_ready = true; _ready = true;
_dirty = false; _dirty = false;
} }
// Descriptive name of the sensor // Descriptive name of the sensor
String description() { String description() {
char buffer[28]; char buffer[28];
snprintf(buffer, sizeof(buffer), "%s @ SwSerial(%u,%u)", pms_specs[_type].name, _pin_rx, _pin_tx);
if (_soft) {
snprintf(buffer, sizeof(buffer), "%s @ SwSerial(%u,%u)", pms_specs[_type].name, _pin_rx, _pin_tx);
} else {
snprintf(buffer, sizeof(buffer), "%s @ HwSerial", pms_specs[_type].name);
}
return String(buffer); return String(buffer);
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) { String slot(unsigned char index) {
char buffer[36] = {0}; char buffer[36] = {0};
snprintf(buffer, sizeof(buffer), "%d @ %s @ SwSerial(%u,%u)", int(index + 1), pms_specs[_type].name, _pin_rx, _pin_tx);
if (_soft) {
snprintf(buffer, sizeof(buffer), "%d @ %s @ SwSerial(%u,%u)", int(index + 1), pms_specs[_type].name, _pin_rx, _pin_tx);
} else {
snprintf(buffer, sizeof(buffer), "%d @ %s @ HwSerial", int(index + 1), pms_specs[_type].name);
}
return String(buffer); return String(buffer);
} }
@ -301,7 +327,7 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
#endif #endif
requestRead(); requestRead();
} }
// Current value for slot # index // Current value for slot # index
@ -310,6 +336,7 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
} }
protected: protected:
bool _soft = true;
unsigned int _pin_rx; unsigned int _pin_rx;
unsigned int _pin_tx; unsigned int _pin_tx;
unsigned long _startTime; unsigned long _startTime;
@ -322,4 +349,4 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
}; };
#endif // SENSOR_SUPPORT && PMS_SUPPORT
#endif // SENSOR_SUPPORT && PMSX003_SUPPORT

code/espurna/sensors/HCSR04Sensor.h → code/espurna/sensors/SonarSensor.h View File

@ -1,16 +1,18 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// HC-SR04 Ultrasonic sensor
// HC-SR04, SRF05, SRF06, DYP-ME007, JSN-SR04T & Parallax PING)))
// Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com> // Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
// Enhancements by Rui Marinho
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && HCSR04_SUPPORT
#if SENSOR_SUPPORT && SONAR_SUPPORT
#pragma once #pragma once
#include "Arduino.h" #include "Arduino.h"
#include "BaseSensor.h" #include "BaseSensor.h"
#include "NewPing.h"
class HCSR04Sensor : public BaseSensor {
class SonarSensor : public BaseSensor {
public: public:
@ -18,17 +20,30 @@ class HCSR04Sensor : public BaseSensor {
// Public // Public
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
HCSR04Sensor(): BaseSensor() {
SonarSensor(): BaseSensor() {
_count = 1; _count = 1;
_sensor_id = SENSOR_HCSR04_ID;
_sensor_id = SENSOR_SONAR_ID;
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Echo pin.
void setEcho(unsigned char echo) { void setEcho(unsigned char echo) {
_echo = echo; _echo = echo;
} }
// Number of iterations to ping in order to filter out erroneous readings
// using a digital filter.
void setIterations(unsigned int iterations) {
_iterations = iterations;
}
// Max sensor distance in centimeters.
void setMaxDistance(unsigned int distance) {
_max_distance = distance;
}
// Trigger pin.
void setTrigger(unsigned char trigger) { void setTrigger(unsigned char trigger) {
_trigger = trigger; _trigger = trigger;
} }
@ -43,22 +58,28 @@ class HCSR04Sensor : public BaseSensor {
return _trigger; return _trigger;
} }
unsigned int getMaxDistance() {
return _max_distance;
}
unsigned int getIterations() {
return _iterations;
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Sensor API // Sensor API
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Initialization method, must be idempotent // Initialization method, must be idempotent
void begin() { void begin() {
pinMode(_echo, INPUT);
pinMode(_trigger, OUTPUT);
digitalWrite(_trigger, LOW);
_sonar = new NewPing(getTrigger(), getEcho(), getMaxDistance());
_ready = true; _ready = true;
} }
// Descriptive name of the sensor // Descriptive name of the sensor
String description() { String description() {
char buffer[24];
snprintf(buffer, sizeof(buffer), "HCSR04 @ GPIO(%u, %u)", _trigger, _echo);
char buffer[23];
snprintf(buffer, sizeof(buffer), "Sonar @ GPIO(%u, %u)", _trigger, _echo);
return String(buffer); return String(buffer);
} }
@ -80,28 +101,11 @@ class HCSR04Sensor : public BaseSensor {
// Current value for slot # index // Current value for slot # index
double value(unsigned char index) { double value(unsigned char index) {
if (index == 0) {
// Trigger pulse
digitalWrite(_trigger, HIGH);
delayMicroseconds(10);
digitalWrite(_trigger, LOW);
// Wait for echo pulse low-high-low
while ( digitalRead(_echo) == 0 ) yield();
unsigned long start = micros();
while ( digitalRead(_echo) == 1 ) yield();
unsigned long travel_time = micros() - start;
// Assuming a speed of sound of 340m/s
// Dividing by 2 since it is a round trip
return 340.0 * (double) travel_time / 1000000.0 / 2;
if (index != 0) return 0;
if (getIterations() > 0) {
return NewPing::convert_cm(_sonar->ping_median(getIterations())) / 100.0;
} }
return 0;
return _sonar->ping_cm() / 100.0;
} }
@ -113,7 +117,10 @@ class HCSR04Sensor : public BaseSensor {
unsigned char _trigger; unsigned char _trigger;
unsigned char _echo; unsigned char _echo;
unsigned int _max_distance;
unsigned int _iterations;
NewPing * _sonar = NULL;
}; };
#endif // SENSOR_SUPPORT && HCSR04_SUPPORT
#endif // SENSOR_SUPPORT && SONAR_SUPPORT

+ 1
- 1
code/espurna/ssdp.ino View File

@ -48,7 +48,7 @@ void ssdpSetup() {
char response[strlen_P(_ssdp_template) + 100]; char response[strlen_P(_ssdp_template) + 100];
snprintf_P(response, sizeof(response), _ssdp_template, snprintf_P(response, sizeof(response), _ssdp_template,
WiFi.localIP().toString().c_str(), // ip
ip.toString().c_str(), // ip
webPort(), // port webPort(), // port
SSDP_DEVICE_TYPE, // device type SSDP_DEVICE_TYPE, // device type
getHostname().c_str(), // friendlyName getHostname().c_str(), // friendlyName


+ 655
- 655
code/espurna/static/index.all.html.gz.h
File diff suppressed because it is too large
View File


+ 298
- 298
code/espurna/static/index.sensor.html.gz.h View File

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

+ 27
- 5
code/espurna/web.ino View File

@ -47,6 +47,8 @@ char _last_modified[50];
std::vector<uint8_t> * _webConfigBuffer; std::vector<uint8_t> * _webConfigBuffer;
bool _webConfigSuccess = false; bool _webConfigSuccess = false;
std::vector<web_request_callback_f> _web_request_callbacks;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// HOOKS // HOOKS
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -93,7 +95,9 @@ void _onGetConfig(AsyncWebServerRequest *request) {
response->printf("{\n\"app\": \"%s\"", APP_NAME); response->printf("{\n\"app\": \"%s\"", APP_NAME);
response->printf(",\n\"version\": \"%s\"", APP_VERSION); response->printf(",\n\"version\": \"%s\"", APP_VERSION);
response->printf(",\n\"backup\": \"1\""); response->printf(",\n\"backup\": \"1\"");
response->printf(",\n\"timestamp\": \"%s\"", ntpDateTime().c_str());
#if NTP_SUPPORT
response->printf(",\n\"timestamp\": \"%s\"", ntpDateTime().c_str());
#endif
// Write the keys line by line (not sorted) // Write the keys line by line (not sorted)
unsigned long count = settingsKeyCount(); unsigned long count = settingsKeyCount();
@ -330,6 +334,19 @@ bool _webKeyCheck(const char * key) {
return (strncmp(key, "web", 3) == 0); return (strncmp(key, "web", 3) == 0);
} }
void _onRequest(AsyncWebServerRequest *request){
// Send request to subscribers
for (unsigned char i = 0; i < _web_request_callbacks.size(); i++) {
bool response = (_web_request_callbacks[i])(request);
if (response) return;
}
// No subscriber handled the request, return a 404
request->send(404);
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool webAuthenticate(AsyncWebServerRequest *request) { bool webAuthenticate(AsyncWebServerRequest *request) {
@ -349,6 +366,10 @@ AsyncWebServer * webServer() {
return _server; return _server;
} }
void webRequestRegister(web_request_callback_f callback) {
_web_request_callbacks.push_back(callback);
}
unsigned int webPort() { unsigned int webPort() {
#if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED
return 443; return 443;
@ -385,6 +406,8 @@ void webSetup() {
#if WEB_EMBEDDED #if WEB_EMBEDDED
_server->on("/index.html", HTTP_GET, _onHome); _server->on("/index.html", HTTP_GET, _onHome);
#endif #endif
// Other entry points
_server->on("/reset", HTTP_GET, _onReset); _server->on("/reset", HTTP_GET, _onReset);
_server->on("/config", HTTP_GET, _onGetConfig); _server->on("/config", HTTP_GET, _onGetConfig);
_server->on("/config", HTTP_POST | HTTP_PUT, _onPostConfig, _onPostConfigData); _server->on("/config", HTTP_POST | HTTP_PUT, _onPostConfig, _onPostConfigData);
@ -401,10 +424,8 @@ void webSetup() {
}); });
#endif #endif
// 404
_server->onNotFound([](AsyncWebServerRequest *request){
request->send(404);
});
// Handle other requests, including 404
_server->onNotFound(_onRequest);
// Run server // Run server
#if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED
@ -413,6 +434,7 @@ void webSetup() {
#else #else
_server->begin(); _server->begin();
#endif #endif
DEBUG_MSG_P(PSTR("[WEBSERVER] Webserver running on port %u\n"), port); DEBUG_MSG_P(PSTR("[WEBSERVER] Webserver running on port %u\n"), port);
// Websocket Callbacks // Websocket Callbacks


+ 4
- 1
code/extra_scripts.py View File

@ -10,7 +10,7 @@ from platformio import util
import distutils.spawn import distutils.spawn
Import("env")
Import("env", "projenv")
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Utils # Utils
@ -86,6 +86,9 @@ def check_size(source, target, env):
# Hooks # Hooks
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Always show warnings for project code
projenv.ProcessUnFlags("-w")
remove_float_support() remove_float_support()
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", check_size) env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", check_size)

+ 4
- 3
code/html/custom.js View File

@ -46,7 +46,7 @@ function sensorName(id) {
"HLW8012", "V9261F", "ECH1560", "Analog", "Digital", "HLW8012", "V9261F", "ECH1560", "Analog", "Digital",
"Events", "PMSX003", "BMX280", "MHZ19", "SI7021", "Events", "PMSX003", "BMX280", "MHZ19", "SI7021",
"SHT3X I2C", "BH1750", "PZEM004T", "AM2320 I2C", "GUVAS12SD", "SHT3X I2C", "BH1750", "PZEM004T", "AM2320 I2C", "GUVAS12SD",
"TMP3X", "HC-SR04", "SenseAir", "GeigerTicks", "GeigerCPM"
"TMP3X", "Sonar", "SenseAir", "GeigerTicks", "GeigerCPM"
]; ];
if (1 <= id && id <= names.length) { if (1 <= id && id <= names.length) {
return names[id - 1]; return names[id - 1];
@ -59,9 +59,10 @@ function magnitudeType(type) {
"Temperature", "Humidity", "Pressure", "Temperature", "Humidity", "Pressure",
"Current", "Voltage", "Active Power", "Apparent Power", "Current", "Voltage", "Active Power", "Apparent Power",
"Reactive Power", "Power Factor", "Energy", "Energy (delta)", "Reactive Power", "Power Factor", "Energy", "Energy (delta)",
"Analog", "Digital", "Events",
"Analog", "Digital", "Event",
"PM1.0", "PM2.5", "PM10", "CO2", "Lux", "UV", "Distance" , "HCHO", "PM1.0", "PM2.5", "PM10", "CO2", "Lux", "UV", "Distance" , "HCHO",
"Local Dose Rate", "Local Dose Rate"
"Local Dose Rate", "Local Dose Rate",
"Count"
]; ];
if (1 <= type && type <= types.length) { if (1 <= type && type <= types.length) {
return types[type - 1]; return types[type - 1];


+ 2
- 4
code/memanalyzer.py View File

@ -55,7 +55,7 @@ def file_size(file):
def analyse_memory(elf_file): def analyse_memory(elf_file):
command = "%s -t '%s' " % (objdump_binary, elf_file)
command = "%s -t '%s'" % (objdump_binary, elf_file)
response = subprocess.check_output(shlex.split(command)) response = subprocess.check_output(shlex.split(command))
if isinstance(response, bytes): if isinstance(response, bytes):
response = response.decode('utf-8') response = response.decode('utf-8')
@ -102,7 +102,7 @@ def run(env_, modules_):
flags = "" flags = ""
for item in modules_.items(): for item in modules_.items():
flags += "-D%s_SUPPORT=%d " % item flags += "-D%s_SUPPORT=%d " % item
command = "export ESPURNA_BOARD=\"WEMOS_D1_MINI_RELAYSHIELD\"; export ESPURNA_FLAGS=\"%s\"; platformio run --silent --environment %s" % (flags, env_)
command = "ESPURNA_BOARD=\"WEMOS_D1_MINI_RELAYSHIELD\" ESPURNA_FLAGS=\"%s\" platformio run --silent --environment %s 2>/dev/null" % (flags, env_)
subprocess.check_call(command, shell=True) subprocess.check_call(command, shell=True)
@ -251,6 +251,4 @@ try:
except: except:
raise raise
subprocess.check_call("export ESPURNA_BOARD=\"\"; export ESPURNA_FLAGS=\"\"", shell=True)
print("\n") print("\n")

+ 45
- 6
code/platformio.ini View File

@ -38,7 +38,7 @@ debug_flags = -DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY = v2 Lower Memory # -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY = v2 Lower Memory
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH = v2 Higher Bandwidth # -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH = v2 Higher Bandwidth
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=400 -DNO_GLOBAL_EEPROM ${env.ESPURNA_FLAGS} -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=400 -DNO_GLOBAL_EEPROM ${sysenv.ESPURNA_FLAGS} -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
build_flags_512k = ${common.build_flags} -Wl,-Teagle.flash.512k0m1s.ld build_flags_512k = ${common.build_flags} -Wl,-Teagle.flash.512k0m1s.ld
build_flags_1m0m = ${common.build_flags} -Wl,-Teagle.flash.1m0m1s.ld build_flags_1m0m = ${common.build_flags} -Wl,-Teagle.flash.1m0m1s.ld
build_flags_4m1m = ${common.build_flags} -Wl,-Teagle.flash.4m1m4s.ld build_flags_4m1m = ${common.build_flags} -Wl,-Teagle.flash.4m1m4s.ld
@ -47,8 +47,8 @@ build_flags_4m3m = ${common.build_flags} -Wl,-Teagle.flash.4m3m4s.ld
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# OTA: # OTA:
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
upload_port = "${env.ESPURNA_IP}"
upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266
upload_port = "${sysenv.ESPURNA_IP}"
upload_flags = --auth="${sysenv.ESPURNA_AUTH}"
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# OTHER SETTINGS: # OTHER SETTINGS:
@ -90,6 +90,7 @@ lib_deps =
rc-switch rc-switch
https://github.com/LowPowerLab/RFM69#1.1.3 https://github.com/LowPowerLab/RFM69#1.1.3
https://github.com/xoseperez/Time https://github.com/xoseperez/Time
NewPing
lib_ignore = lib_ignore =
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -129,7 +130,7 @@ board = ${common.board_1m}
board_build.flash_mode = ${common.flash_mode} board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps} lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore} lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -D${env.ESPURNA_BOARD}
build_flags = ${common.build_flags_1m0m} -D${sysenv.ESPURNA_BOARD}
upload_speed = ${common.upload_speed} upload_speed = ${common.upload_speed}
upload_port = ${common.upload_port} upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags} upload_flags = ${common.upload_flags}
@ -142,7 +143,7 @@ board = ${common.board_4m}
board_build.flash_mode = ${common.flash_mode} board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps} lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore} lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_4m1m} -D${env.ESPURNA_BOARD}
build_flags = ${common.build_flags_4m1m} -D${sysenv.ESPURNA_BOARD}
upload_speed = ${common.upload_speed} upload_speed = ${common.upload_speed}
upload_port = ${common.upload_port} upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags} upload_flags = ${common.upload_flags}
@ -188,6 +189,18 @@ extra_scripts = ${common.extra_scripts}
# DEVELOPMENT BOARDS # DEVELOPMENT BOARDS
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
[env:wemos-d1mini]
platform = ${common.platform}
framework = ${common.framework}
board = d1_mini
board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DWEMOS_D1_MINI -DDEBUG_FAUXMO=Serial -DNOWSAUTH
upload_speed = ${common.upload_speed_fast}
monitor_speed = ${common.monitor_speed}
extra_scripts = ${common.extra_scripts}
[env:wemos-d1mini-relayshield] [env:wemos-d1mini-relayshield]
platform = ${common.platform} platform = ${common.platform}
framework = ${common.framework} framework = ${common.framework}
@ -535,7 +548,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_DUAL_R2 build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_DUAL_R2
extra_scripts = ${common.extra_scripts} extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-dual-ota-r2]
[env:itead-sonoff-dual-r2-ota]
platform = ${common.platform} platform = ${common.platform}
framework = ${common.framework} framework = ${common.framework}
board = ${common.board_1m} board = ${common.board_1m}
@ -2348,6 +2361,32 @@ upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags} upload_flags = ${common.upload_flags}
extra_scripts = ${common.extra_scripts} extra_scripts = ${common.extra_scripts}
[env:homecube-16a]
platform = ${common.platform}
framework = ${common.framework}
board = ${common.board_1m}
board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -DHOMECUBE_16A
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
extra_scripts = ${common.extra_scripts}
[env:homecube-16a-ota]
platform = ${common.platform}
framework = ${common.framework}
board = ${common.board_1m}
board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -DHOMECUBE_16A
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags}
extra_scripts = ${common.extra_scripts}
[env:bh-onofre] [env:bh-onofre]
platform = ${common.platform} platform = ${common.platform}
framework = ${common.framework} framework = ${common.framework}


Loading…
Cancel
Save