diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..164b7a6e --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,41 @@ +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 120 + +# 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. +daysUntilClose: 30 + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - enhancement + - bug + - staged for release + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed in 30 days if no further activity occurs. + Thank you for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +closeComment: > + This issue will be auto-closed because there hasn't been any activity for a few months. Feel free to open a new one if you still experience this problem. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +only: issues diff --git a/.gitignore b/.gitignore index 4a2aa300..e61c68af 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,10 @@ firmware* .gcc-flags.json .sconsign.dblite credentials.h -.build node_modules code/utils custom.h +.python +.env +.DS_Store +.vscode diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..52d9af97 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +language: python +python: +- '2.7' +sudo: false +cache: + directories: + - "~/.platformio" +install: +- pip install -U platformio +- cd code ; npm install --only=dev ; cd .. +script: +- cd code && ./build.sh && cd .. +before_deploy: +- mv firmware/*/espurna-*.bin firmware/ +deploy: + provider: releases + api_key: + secure: LMCdaQnCxSQ5EuKhqcFR6VTfDCWc06jwD4fdHfkmBaeWBMMzdoZEqN26AwdTnoLLlQJTR9l21NypgGybssBr69Md/ZinMahWCJJ4gVzPe9Adr9ijRbzj/wckirLBVZjRWn8fxTjJgjpu1ten2CgBfNcc/roN3fI6DV/1Fvv1REfihND4EeIermsxIVRXOyluu1vnPV9ZM28XBNch9XfkKwIpLEaHNNtkzlSEua39U34WpZShrxxEVoZhiF/R1ZF+NiAnursPcPsn5hdrXyHFLFT2dVDnlpdIp79c6SGkCZ636//5erB6hgBHshbwuT9TYXxtwLyL7AeN/MfCg0gtZSsDII8mLKzytW1tl7r1W9l7s21z/55tljSz2Z6dcbJC3bxucgcLxM9R6PrsPdDrPQTd0QwYqYalMNlfuA8KGcesZueqI9Q4uw7uHFUwIp7FIaoKhwhjTKe/ZHZ75zU4wdBTXof4dnSQOudoGGjRyyj7V0eR/Mhuni45N2Bldy9hDaldgtWMuEdx3ABW1IrPXtPDVTXM6QjUHm0nj5zzCgoCvQEw3jycA7Wlgbzo8MQkKH3u4MtupJcEGHJAqMbk+JlRpIfdWTiqtI697CReRGYSWT6YxF68TeJo77JPPph724BIBMtKtIk2+4RkHxz5RqM8O2vt+AFNjnWNIvVQtY8= + file_glob: true + file: firmware/espurna-*.bin + skip_cleanup: true + on: + all_branches: true + tags: true +notifications: + pushover: + api_key: + secure: wtAleSibUqDOH7KskYMIFXwNqqZMA/2flCJzu835hSFWDFTjdXGeYLmQxCI7FGTWHcvWgf5pt3KR3OXtABVDfwqLj0HZjEubIypm56mZKsEaP32JlQiAw+Qz1KSU/5gEKEI3NU5MuL1rIebSEo9iVgwVDMn51GI9qv0LbjLKfXpxBmJXL/OmBRggVMswScCppXJLVlyMSRj9qT0Ds/lz+SL1g6vZHPO8r3z1BSOMA0eWNUYd/Huhe1XAHYzS4mS3aybPsPKldpv0igsvE5BHT37rb43QA0pHxv2M09QlBRNBI6kHgxzCw2OJ4uz5/K2U/4LBMDJrAj6rUGAhKn8Wuiw4B/kZb+WsvRCcCTHGYTc20KWrrV4aOojQRLht1FgNg7Ub+NNm5T9LBG+XKKHARTv1Kv09nCpPVD8NvF5YPRsSb7ZL6s/wUGSNuu365aVs3BnnazXb+ha33Hg0bCBEwmlW6FKdQ7S8OYsoIobTUcporRs8p089EQ8vNxN0osHnKPX5M0ZOxbBOIt5fQO2B+Cdn+m4hx/DETM5HMLZ/GpsbY9eiN7HWaaQPicSrSLprY6tzfvcHePk9Y6t8rjCKzehwlYtrfiMRvrPhZuOLcB4s3OmJngxvOCGxdWkh/6F2CY6sDslyviaK0ZwX93Gn7uNThAviFpZNUlPWP6jHIkA= + users: + secure: atCRvGYPuAT1DH5UupNIV80sqrIgwdYrxO69tq+lIBfi3BIJ4LLlvUQwigWak6otfJbEqAQKVNi8I8J4g7ASHx1wn335vpAqLAbhJqfbLznAcU9nZ+bdc8+NJ57qY66ZZJNpljbMC0HWgw2kgyiCLJ1wS3zsQAyuzyGuMcmc43zFOQMA7QUaefE6LGlHPn0i6Ub04QgQ1413IEu2/FR5i4hVXrgRQzaPy07pSPbvFTvoxfWDgWjTQM+R2AG8uStesO+2yzeb8Nu2pJDvFf3R1N8P2e3zg5YN86DLNRQ+Kxl7M1FJ/txbJ/4D1jdNwAmtUzEoYnsKCcCnMHWGuSlJF8fgXSVBDi9KVH7Y6rlWXzMcqesR5lzNTlD7JQ01yw2WrO6Nj7fvan+QNGp3d5F4Kf3WE+5rkmM5Sbo5rb9YOGt688i1qJ3Xf1MTkQNCzDiAg3qf1hu8j+AALblY73gNSAgv4F+/SnmnfKy5Cz/oRQQfboiC/VphNa25Fzq3s3uahQfLha4tyHrc1LltSM6bztErRSPqDp96qVTQORVHr6jqJhl6c9R0XXrnc0Pc5lpBoPKOqug1yPp15k9AAssGxtXZqg2loHjwmS+Qm1i77mNGKNhzqDpmLHEzmIejc4n4lIZmze+dLucStiNnkN6TF3nvIh37CNjH6slT5t7WfJg= diff --git a/CHANGELOG.md b/CHANGELOG.md index 289778ef..6177350c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,18 +3,270 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [1.12.6] 2018-05-02 +### Fixed +- Check NTP_SUPPORT for sensors (thanks to @mcspr) +- Fix AM2302 sensor +- Fix hostname truncated to 20 chars when advertised to DHCP ([#774](https://github.com/xoseperez/espurna/issues/774)) +- Decouple Serial object from Terminal, Debug modules ([#787](https://github.com/xoseperez/espurna/issues/787)) +- Fix Arilux LC-01 definitions ([#797](https://github.com/xoseperez/espurna/issues/797)) +- Do not uppercase hostname in web interface ([#799](https://github.com/xoseperez/espurna/issues/799)) +- Ensure scheduler has access to all channels independently of the color mode ([#807](https://github.com/xoseperez/espurna/issues/807)) + +### Added +- Support for IteadStudio Sonoff S31 ([#497](https://github.com/xoseperez/espurna/issues/497)) +- Option to ignore daylight saving in scheduler ([#783](https://github.com/xoseperez/espurna/issues/783)) +- Report last energy reset datetime in web interface ([#784](https://github.com/xoseperez/espurna/issues/784)) +- Added captive portal in AP mode +- Support for IR toggle mode (thanks to @darshkpatel) +- Support for IteadStudio Sonoff POW R2 (thanks to @ColinShorts) +- Support for Luani HVIO (thanks to @wildwiz) +- Support for Zhilde ZLD-EU55-W power strip (thanks to @wildwiz) +- Support for RFB_DIRECT Sonoff Bridge EFM8BB1 bypass hack (thanks to @wildwiz) +- Support for SenseAir S8 CO2 sensor (thanks to @Yonsm) +- Support for PMS5003T/ST sensors (thanks to @Yonsm) + +### Changed +- Updated JustWifi Library +- Some cleanup in the web interface +- Refactored configuration files (thanks to @lobradov, @mcspr) +- Changes pre-commit hook (thanks to @mcspr) + +## [1.12.5] 2018-04-08 +### Fixed +- Fixed expected power calibration ([#676](https://github.com/xoseperez/espurna/issues/676)) +- Do not show empty time strings ([#691](https://github.com/xoseperez/espurna/issues/691), thanks to @PieBru) +- Fix load average calculation when system check is disabled ([#707](https://github.com/xoseperez/espurna/issues/707)) +- Fixed unstability issues with NtpClientLib using temporary fork ([#743](https://github.com/xoseperez/espurna/issues/743)) +- Fixed typos in homeassistant module (thanks to @Cabalist) +- Fixed default HLW8012 calibration for KMC devices (thanks to @gn0st1c) +- Fix MQTT query request +- Fix scheduler debug message +- Fix NTP offset value + +### Added +- Option to change NTP timeout via compile-time setting ([#452](https://github.com/xoseperez/espurna/issues/452)) +- Added humidity correction to web UI ([#626](https://github.com/xoseperez/espurna/issues/626), tahnks to @ManuelW77) +- Added support for USA DST calculation ([#664](https://github.com/xoseperez/espurna/issues/664)) +- Option to reset energy count ([#671](https://github.com/xoseperez/espurna/issues/671)) +- Added Sonoff SV prebuild image ([#698](https://github.com/xoseperez/espurna/issues/698), thanks to @akasma74) +- Check and remove unused config keys ([#730](https://github.com/xoseperez/espurna/issues/730)) +- Visual Studio metadata files added to .gitignore ([#731](https://github.com/xoseperez/espurna/issues/731), thanks to @gn0st1c) +- Added default MQTT and SSL settings to web UI ([#732](https://github.com/xoseperez/espurna/issues/732), thanks to @mcspr) +- Added option to the web UI to set the light transition length in milliseconds ([#739](https://github.com/xoseperez/espurna/issues/739)) +- Improved testing with Travis (thanks to @lobradov) +- Change dimmers using schedule (thanks to @wysiwyng) +- Debug console in web UI (thanks to @lobradov), including command execution +- Option to reset relays in MQTT disconection (thanks to @a-tom-s) +- Option to disable system check from custom header (thanks to @phuonglm) +- Added "board" topic to the heartbeat messages (thanks to @mcspr) +- Added methods to create hierarchical MQTT JSON responses +- Added RESET.SAFE command to reboot into safe mode +- Added SDK and Core versions to the web UI +- Added revision to web UI (only when built from build.sh) +- Support for OBI Powerplug Adapter ([#622](https://github.com/xoseperez/espurna/issues/622), thanks to @Geitde) +- Support for Tunbox Powerstrip02 (thanks to @gn0st1c) +- Support for Lingan SWA1 (thanks to @gn0st1c) +- Support for Heygo HY02 (thanks to @gn0st1c) +- Support for Maxcio WUS0025 (thanks to @gn0st1c) +- Support for Yidian XSSSA05 SWA1 (thanks to @gn0st1c) +- Support for ArnieX Swifitch (thanks to @LubergAlexander) +- Support for IKE ESPIKE board +- Support for AM2320 sensors via I2C (thanks to @gn0st1c) +- Support for GUVAS12SD sensor (thanks to @gn0st1c) + +### Changed +- Removed hostname size limit ([#576](https://github.com/xoseperez/espurna/issues/576), [#659](https://github.com/xoseperez/espurna/issues/659)) +- Reworked RGBW implementation (thanks to @Skaronator) +- Several web UI layout changes (thanks to @lobradov & @mcspr) +- Button MQTT messages will not have the retain flag (thanks to @lobradov) +- Remove unnecessary code from boot log (thanks to @gn0st1c) +- Updated logo and favicon, added gitter channel +- Force reporting power values as 0 if relay is off +- Using gulp-crass for CSS minification +- Using WIFI_NONE_SLEEP by default + +## [1.12.4] 2018-03-05 +### Fixed +- Adding a 1ms delay after UDP send to avoid loosing packets ([#438](https://github.com/xoseperez/espurna/issues/438)) +- Fixed void return in BMX280 sensor ([#489](https://github.com/xoseperez/espurna/issues/489)) +- Fix MQTT keep alive cannot be more than 255 seconds ([#515](https://github.com/xoseperez/espurna/issues/515)) +- Do not show scheduler tab in Web UI if build without scheduler support ([#527](https://github.com/xoseperez/espurna/issues/527)) +- Fix inline documentation for Sonoff 4CH Pro button modes ([#551](https://github.com/xoseperez/espurna/issues/551)) +- Prevent resending messages from rfin in RF Bridge ([#561](https://github.com/xoseperez/espurna/issues/561)) +- Fix AnalogSensor description ([#601](https://github.com/xoseperez/espurna/issues/601)) +- Fixed missing setting in HASS WS callback (thanks to @mcspr) +- ECH1560 call sync from tick method +- Fixed several issues reported by codacy + +### Added +- UART to MQTT module (thanks to Albert Weterings, [#529](https://github.com/xoseperez/espurna/issues/529)) +- Added option to show HASS configuration code in ESPurna web UI ([#616](https://github.com/xoseperez/espurna/issues/616)) +- OTA upgrade via terminal (using 'ota' command, with SSL support) +- Added I2C scan and clear commands to terminal (only when I2C enabled) +- Added new relay & wifi led mode ([#604](https://github.com/xoseperez/espurna/issues/604)) +- Option to enable/disable web auth from web UI +- Added "Reset to factory settings" in web UI (thanks to Teo Pavel, [#569](https://github.com/xoseperez/espurna/issues/569)) +- Added {magnitude} placeholder to MQTT root topic +- Option to report energy in kWh and power in kW ([#523](https://github.com/xoseperez/espurna/issues/523)) +- Check upgrade file size and signature in web UI +- Automatically dump info on telnet connection if TERMINAL_SUPPORT is disabled +- Two different ESPURNA_CORE images for 1MB and 4MB boards, freeing GPIOs ([#557](https://github.com/xoseperez/espurna/issues/557)) +- Initial support for PZEM004T sensor (still beta) +- Support for STM_RELAY board (thanks to Maciej Czerniak) +- Support for KMC 70011 energy monitor (thanks to Wayne Manion, [#598](https://github.com/xoseperez/espurna/issues/598)) +- Support for Wifi Stecker Shuko device (thanks to @Geitde, [#622](https://github.com/xoseperez/espurna/issues/622)) +- Support for GizWits Witty Cloud device (thanks to Theonedemon) + +### Changed +- BMX280 changes to allow for hot-plug ([#353](https://github.com/xoseperez/espurna/issues/353)) +- Increase the initial check interval for NTP ([#452](https://github.com/xoseperez/espurna/issues/452)) +- Force turning relays off before turning others on when synced ([#491](https://github.com/xoseperez/espurna/issues/491)) +- Publish slampher as light to Home Assistant ([#494](https://github.com/xoseperez/espurna/issues/494)) +- Force API to return the target status of the relay ([#548](https://github.com/xoseperez/espurna/issues/548)) +- Increasing max number of messages in JSON payload to 20 ([#588](https://github.com/xoseperez/espurna/issues/588)) +- Change copy from 'Use colorpicker' to 'Use color'. Better hint. ([#590](https://github.com/xoseperez/espurna/issues/590)) +- Completely reworked the RF module to use the same web UI as the RFBridge module to learn new codes ([#594](https://github.com/xoseperez/espurna/issues/594)) +- Several spelling and grammar changes by Lee Marlow +- Always enabled telnet access in ESPURNA_CORE image +- Updated ESPSoftwareSerial, ESPAsyncTCP and ESPAsyncWebServer libraries + +### Removed +- Remove dependency from gulp-util ([#493](https://github.com/xoseperez/espurna/issues/493)) +- Removed specific support for Magic Home LED Controller 2.3 ([#512](https://github.com/xoseperez/espurna/issues/512)) +- Disabled floating point support when building against Arduino Core 2.4.0 with PIO +- Removed WiFi distance calculation + +## [1.12.3] 2018-01-29 +### Fixed +- Fix telnet crash due to local reference ([#487](https://github.com/xoseperez/espurna/issues/487)) + +## [1.12.2] 2018-01-29 +### Added +- Repository migrated over to GitHub +- Travis CI build test and deploy +- Pre-commit hook to change README.md file depending on the branch +- {hostname} and {mac} placeholders for MQTT root topic +- Added support for timezones with minutes ([#265](https://github.com/xoseperez/espurna/issues/265)) +- SSDP support ([#282](https://github.com/xoseperez/espurna/issues/282), [#423](https://github.com/xoseperez/espurna/issues/423), disabled by default since current implementation is not compatible with Alexa [#479](https://github.com/xoseperez/espurna/issues/479)) +- HA auto-discover for multi-relay boards and sensors ([#392](https://github.com/xoseperez/espurna/issues/392), [#465](https://github.com/xoseperez/espurna/issues/465)) +- Reset the pulse timeout every time an MQTT message is sent with the non-normal payload value ([#454](https://github.com/xoseperez/espurna/issues/454)) +- Option to disable schedules without deleting them ([#453](https://github.com/xoseperez/espurna/issues/453)) +- Added LED_MODE_STATUS ([#458](https://github.com/xoseperez/espurna/issues/458)) +- Support to set on/off state per channel using switches ([#457](https://github.com/xoseperez/espurna/issues/457)) +- Added support for MagicHome LED Controller 2.3 +- Alexa message queue (thanks to Qubeck) +- Secondary Serial RX port for H801 and H802 boards ([#386](https://github.com/xoseperez/espurna/issues/386), thanks to Pablo Pousada Rial) +- Added compatibility with https://github.com/rhx/RF-Bridge-EFM8BB1 to RF Bridge (Thanks to Rene Hexel) +- Added message queue to RF Bridge +- Added MAC to mDNS text fields +- Added wifi.ap command to go into AP mode +- Added message id on MQTT JSON payloads +- Added hooks for 3rd party code (custom modules) +- Local broker to broadcast messages internally +- Added timestamp to debug output +- Common I2C interface to abstract backend library (Wire or Brzo I2C) +- Added espurnaLoopRegister + +### Fixed +- Fixed support for 4CH Pro different modes ([#333](https://github.com/xoseperez/espurna/issues/333)) +- Fixed several sensor modules to enable hot-unplug-plug ([#398](https://github.com/xoseperez/espurna/issues/398)) +- Fixed crash when calling idbSend from an MQTT callback ([#410](https://github.com/xoseperez/espurna/issues/410)) +- Checking trailing slash in mqttTopic ([#422](https://github.com/xoseperez/espurna/issues/422)) +- Fixed pulse and pulse_ms order in relay_t structure ([#424](https://github.com/xoseperez/espurna/issues/424)) +- Use same buffer size across all terminal-realted classes/methods. Set to 128 chars ([#477](https://github.com/xoseperez/espurna/issues/477), [#478](https://github.com/xoseperez/espurna/issues/478)) +- Fix WiFi scan status in web UI +- Several code quality fixes (thanks to @lobradov) +- Fixed error message on first command over telnet + +### Changed +- BMX280 sensor module now doesn't depend on third party libraries +- Changed time management in ntp, mqtt and scheduler modules + +## Deprecated +- {identifier} placeholder for MQTT root topic + +## [1.12.1] 2018-01-14 +### Added +- Option to perform a WiFi network scan from web UI +- Added hostname to web UI side menu ([#404](https://github.com/xoseperez/espurna/issues/404)) +- Option to flash multiple devices with ESPurna OTA Manager + +### Fixed +- Fix web UI layout so signature does not overlay buttons ([#396](https://github.com/xoseperez/espurna/issues/396)) +- Option to disable network scan and allow connecting to hidden SSID ([#392](https://github.com/xoseperez/espurna/issues/392), [#399](https://github.com/xoseperez/espurna/issues/399)) +- Fix crash caused by a delay in UDP debugging code ([#397](https://github.com/xoseperez/espurna/issues/397)) +- Fix memory leak in influxDB module ([#410](https://github.com/xoseperez/espurna/issues/410)) +- Fix typos in web UI ([#394](https://github.com/xoseperez/espurna/issues/394), [#421](https://github.com/xoseperez/espurna/issues/421)) + +### Changed +- Updated to fauxmoESP 2.4.2 +- Changed default I2C GPIO for Wemos D1 ([#420](https://github.com/xoseperez/espurna/issues/420)) +- Some terminal commands have changed. See docs or type "help". + +## [1.12.0] 2018-01-11 +### Added +- Scheduler (contributed by Stefano Cotterli, thank you!, [#131](https://github.com/xoseperez/espurna/issues/131)) +- Added "wifi.scan" command to terminal +- Added ESPurna Switch board support +- Added support for python3 in memanalyzer and ota scripts (thanks to @Cabalist) +- Added BSSID, RSSI, channels and distance to web UI status tab +- Added mDNS name resolving to MQTT, InfluxDB and NoFUSS modules ([#129](https://github.com/xoseperez/espurna/issues/129), disabled by default) + +### Fixed +- Update FauxmoESP library to 2.4.1, solves dependency issue ([#388](https://github.com/xoseperez/espurna/issues/388)) +- Fixed hardware definition in Sonoff Basic and Dual R2 causing wrong relay state on boot ([#365](https://github.com/xoseperez/espurna/issues/365)) + +### Changed +- Removed auto-recursion check in Domoticz module ([#379](https://github.com/xoseperez/espurna/issues/379)) +- Rename terminal commands: reset.wifi to wifi.reset, reset.mqtt to mqtt.reset. +- Update JustWifi library to 1.1.6 (support for multiple SSIDs with the same name) +- Changed the way Home Assistant module handles disabling auto-discovery ([#383](https://github.com/xoseperez/espurna/issues/383)) + +## [1.11.4] 2018-01-09 +### Fixed +- Fix bug in RF Bridge when RF code contains the stop byte. Check overflow ([#357](https://github.com/xoseperez/espurna/issues/357)) +- Fixed typos in code and wiki (Thanks to @Cabalist) +- Fix bug in magnitude topic and units ([#355](https://github.com/xoseperez/espurna/issues/355)) + +### Added +- Small core build to allow two-step flashing method for big binaries +- Thingspeak support ([#371](https://github.com/xoseperez/espurna/issues/371), disabled by default) +- Color synchronization between lights using MQTT ([#362](https://github.com/xoseperez/espurna/issues/362)) +- Support for Arilux AL-LC02 ([#347](https://github.com/xoseperez/espurna/issues/347)) +- Support for Tarpuna Shield for Wemos D1 +- Build option to disable password checking ([#373](https://github.com/xoseperez/espurna/issues/373)) +- Option to report sensor address via MQTT ([#377](https://github.com/xoseperez/espurna/issues/377), I2C address, GPIO, Dallas address,...) +- Added binary size to memanalyzer script +- Option to specify custom client ID for MQTT connection ([#368](https://github.com/xoseperez/espurna/issues/368)) +- Cross-platform ESPurna OTA Manager implemented in python (untested) +- Terminal command to get or set digital GPIO + +### Changed +- Using 2.3.0 for prebuilt binaries +- Fix delay in DHT sensor +- Allow MQTT keep alive value of up to 3600s +- Changed Sonoff 4CH Pro definitions to support built-in interlock mode ([#333](https://github.com/xoseperez/espurna/issues/333)) + +## [1.11.3] 2018-01-02 +### Fixed +- Fix uninitialized PWM channels bug ([#356](https://github.com/xoseperez/espurna/issues/356)) + +### Added +- Added memory analyzer + ## [1.11.2] 2017-12-30 ### Fixed -- Fix my92xx and pwm references for Arduino IDE (#346) -- Fix SHT3X I2C sensor magnitude count (#337) -- Fix timing for DHT11 sensors (#294) -- Fix overflow in relayParsePayload with long MQTT messages (#344) -- Fix loading of Dallas and DHT sensors for Sonoff TH images (#352) +- Fix my92xx and pwm references for Arduino IDE ([#346](https://github.com/xoseperez/espurna/issues/346)) +- Fix SHT3X I2C sensor magnitude count ([#337](https://github.com/xoseperez/espurna/issues/337)) +- Fix timing for DHT11 sensors ([#294](https://github.com/xoseperez/espurna/issues/294)) +- Fix overflow in relayParsePayload with long MQTT messages ([#344](https://github.com/xoseperez/espurna/issues/344)) +- Fix loading of Dallas and DHT sensors for Sonoff TH images ([#352](https://github.com/xoseperez/espurna/issues/352)) - Subscribe to Domoticz MQTT topics only if Domotic< is enabled ### Added -- Added option to change MQTT retain flag, QoS and keepalive time from webUI (#321) -- Added LED modes "always off" and "always on" (#348) +- Added option to change MQTT retain flag, QoS and keepalive time from webUI ([#321](https://github.com/xoseperez/espurna/issues/321)) +- Added LED modes "always off" and "always on" ([#348](https://github.com/xoseperez/espurna/issues/348)) - Defined new ESPurna switch (no HLW8012 support & touch button ready) ### Changed @@ -31,12 +283,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.11.0] 2017-12-28 ### Fixed -- Fixed Arduino IDE compilation issues (#330) +- Fixed Arduino IDE compilation issues ([#330](https://github.com/xoseperez/espurna/issues/330)) - Fixed issues with IE - Fixed websocket auth issue with Safari (temporary) - Fixed MQTT group sync when different switches share same group -- Fixed casting issue in buttonStore (#327) -- Fixed crash in InfluxDB initial heartbeat (#318) +- Fixed casting issue in buttonStore ([#327](https://github.com/xoseperez/espurna/issues/327)) +- Fixed crash in InfluxDB initial heartbeat ([#318](https://github.com/xoseperez/espurna/issues/318)) - Fixed LED logic for ESPurna H08 board ### Added @@ -47,54 +299,54 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Option to select sensor read interval and report interval from web UI - Itead RF Bridge + Match MQTT RFOUT codes to relays - + Force RFBridge to send messages even if switch is already in requested state (#324) + + Force RFBridge to send messages even if switch is already in requested state ([#324](https://github.com/xoseperez/espurna/issues/324)) + Implemented RFbridge message queue asynchronously -- Added option to load config via HTTP POST & reset (#335) -- Added option to define behaviour of the first LED between WIFI, MQTT, FIND-ME (#317) +- Added option to load config via HTTP POST & reset ([#335](https://github.com/xoseperez/espurna/issues/335)) +- Added option to define behaviour of the first LED between WIFI, MQTT, FIND-ME ([#317](https://github.com/xoseperez/espurna/issues/317)) - Added HTML linter to gulp builder -- Added Help command on terminal (#338) -- Added preliminary support for SSDP (untested, disabled by default) (#282) +- Added Help command on terminal ([#338](https://github.com/xoseperez/espurna/issues/338)) +- Added preliminary support for SSDP (untested, disabled by default) ([#282](https://github.com/xoseperez/espurna/issues/282)) - Reporting NTP datetime on MQTT heartbeat (thanks to Eldon R. Brown) - Added version tracking and migration code - I2C and GPIO locking features -- Changed default button action for touch button devices (TOUCH and T1) (#327) -- Generic 8 channel board (#336) +- Changed default button action for touch button devices (TOUCH and T1) ([#327](https://github.com/xoseperez/espurna/issues/327)) +- Generic 8 channel board ([#336](https://github.com/xoseperez/espurna/issues/336)) ### Changed - Added more sensor data filters (Max, MobileAverage) -- Changed max pulse time to 1h (#316) -- Renamed "reset" to "reboot" for clarity (#315) +- Changed max pulse time to 1h ([#316](https://github.com/xoseperez/espurna/issues/316)) +- Renamed "reset" to "reboot" for clarity ([#315](https://github.com/xoseperez/espurna/issues/315)) - UI refactor - Change apiRegister signature ## [1.10.1] 2017-12-05 ### Fixed -- Fix Sonoff RFBridge learn message from web UI (#287) -- Fix unstability in "one and just one" sync mode (#290) -- Fix unnecessary inclusion of my92xx library (#293) -- Limit the MQTT queue to 10 messages when "Use JSON payload" enabled (#296) -- Fix Sonoff RFBridge OFF button toggling switch (#303) -- Allow defining only ON or OFF codes in Sonoff RFBridge (#304) -- Disabled terminal support for Sonoff Dual (#310) +- Fix Sonoff RFBridge learn message from web UI ([#287](https://github.com/xoseperez/espurna/issues/287)) +- Fix unstability in "one and just one" sync mode ([#290](https://github.com/xoseperez/espurna/issues/290)) +- Fix unnecessary inclusion of my92xx library ([#293](https://github.com/xoseperez/espurna/issues/293)) +- Limit the MQTT queue to 10 messages when "Use JSON payload" enabled ([#296](https://github.com/xoseperez/espurna/issues/296)) +- Fix Sonoff RFBridge OFF button toggling switch ([#303](https://github.com/xoseperez/espurna/issues/303)) +- Allow defining only ON or OFF codes in Sonoff RFBridge ([#304](https://github.com/xoseperez/espurna/issues/304)) +- Disabled terminal support for Sonoff Dual ([#310](https://github.com/xoseperez/espurna/issues/310)) ### Added -- Support for SI7021-based sensor by Itead Studio compatible with Sonoff TH (#216) -- Support for Sonoff Dual R2 (#286) -- MQTT group topics (sync two or more switches from different devices, #300) +- Support for SI7021-based sensor by Itead Studio compatible with Sonoff TH ([#216](https://github.com/xoseperez/espurna/issues/216)) +- Support for Sonoff Dual R2 ([#286](https://github.com/xoseperez/espurna/issues/286)) +- MQTT group topics (sync two or more switches from different devices, [#300](https://github.com/xoseperez/espurna/issues/300)) - Color transitions (enabled by default, can be disabled from web UI) - Option to disable MQTT support at build time ### Changed - Decreased PWM frequency for dimmer lights -- Changed password policy (#297) +- Changed password policy ([#297](https://github.com/xoseperez/espurna/issues/297)) ## [1.10.0] 2017-11-26 ### Fixed - Temperatures with 1 decimal resolution - Issues with Sonoff B1 due to bad driver management (using my92xx library now) -- Avoid recursive messages on Domoticz (#272) +- Avoid recursive messages on Domoticz ([#272](https://github.com/xoseperez/espurna/issues/272)) - Fixed Sonoff T1 configuration -- Simplify and fix web auth (#284) +- Simplify and fix web auth ([#284](https://github.com/xoseperez/espurna/issues/284)) - Fix Embedis custom parser ### Added @@ -102,16 +354,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Option to disable system check on build time - Power saving features (loopDelay and wifi sleep) - Added Sonoff TH build environment -- Send Home Assistant auto discover messages on connect (#279) -- Implemented Home Assistant availability topic (#280) +- Send Home Assistant auto discover messages on connect ([#279](https://github.com/xoseperez/espurna/issues/279)) +- Implemented Home Assistant availability topic ([#280](https://github.com/xoseperez/espurna/issues/280)) - Update time, uptime and heap on webUI every heartbeat -- Support for LLMNR and NetBIOS (#282) +- Support for LLMNR and NetBIOS ([#282](https://github.com/xoseperez/espurna/issues/282)) - Added I2C clean bus code - Added realm to auth challenge ### Changed - Changed default hostname to "ESPURNA_XXXXXX" -- Binaries built against stable core (~40Kb less, #274) +- Binaries built against stable core (~40Kb less, [#274](https://github.com/xoseperez/espurna/issues/274)) - Enabled TERMINAL_SUPPORT for Sonoff Dual (only available via TELNET) - Dinamically resize debug strings (now messages are not cropped) - MQTT: unsubscribe to '#' before subscribing @@ -125,7 +377,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed bug in MY9291-based light bulbs at full brightness ### Added -- RFBridge: toggle when RF codes for ON and OFF are the same (#270) +- RFBridge: toggle when RF codes for ON and OFF are the same ([#270](https://github.com/xoseperez/espurna/issues/270)) - Support for HSV color schema (MQTT, API and webUI via a selector) ### Changed @@ -133,9 +385,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.9.8] 2017-11-08 ### Fixed -- Removed dimmer lights flicker when saving to EEPROM (#191) -- Fixed low brightness in dimmer lights (#157) -- Fixed blank fields in energy (#258, #259) +- Removed dimmer lights flicker when saving to EEPROM ([#191](https://github.com/xoseperez/espurna/issues/191)) +- Fixed low brightness in dimmer lights ([#157](https://github.com/xoseperez/espurna/issues/157)) +- Fixed blank fields in energy ([#258](https://github.com/xoseperez/espurna/issues/258), [#259](https://github.com/xoseperez/espurna/issues/259)) - Fixed support for Arilux AL-LC06 - Updated fauxmoESP library with support for GetBinaryState actions @@ -154,42 +406,42 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.9.7] 2017-10-25 ### Fixed -- Fix Alexa interface switching on all lights (#256) +- Fix Alexa interface switching on all lights ([#256](https://github.com/xoseperez/espurna/issues/256)) ## [1.9.6] 2017-10-23 ### Fixed -- Fix power report in Domoticz (#236) -- Fix Sonoff POW in AP mode (#241) -- Fix Home Automation auto-discovery (support for single relay switches and RGB lights, #235) +- Fix power report in Domoticz ([#236](https://github.com/xoseperez/espurna/issues/236)) +- Fix Sonoff POW in AP mode ([#241](https://github.com/xoseperez/espurna/issues/241)) +- Fix Home Automation auto-discovery (support for single relay switches and RGB lights, [#235](https://github.com/xoseperez/espurna/issues/235)) - Check WS authentication only on start event ### Added -- Support for 2.4.0 RC2 Arduino Core that fixes KRACK vulnerablity (pre-built images are compiled against this, #242) +- Support for 2.4.0 RC2 Arduino Core that fixes KRACK vulnerablity (pre-built images are compiled against this, [#242](https://github.com/xoseperez/espurna/issues/242)) - Support for ManCaveMade ESPLive board (thanks to Michael A. Cox) - Support for InterMIT Tech QuinLED 2.6 (thanks to Colin Shorts) -- Support for Magic Home LED Controller 2.0 (thanks to users @gimi87 and @soif, #231) +- Support for Magic Home LED Controller 2.0 (thanks to users @gimi87 and @soif, [#231](https://github.com/xoseperez/espurna/issues/231)) - Support for Arilux AL-LC06 (thanks to Martijn Kruissen) -- Support for Xenon SM-PW702U Wifi boards (thanks to Joshua Harden, #212) -- Support for Authometion LYT8266 (testing, thanks to Joe Blellik, #213) -- Support for an external button for D1 Mini boards (thanks to user @PieBru, #239) +- Support for Xenon SM-PW702U Wifi boards (thanks to Joshua Harden, [#212](https://github.com/xoseperez/espurna/issues/212)) +- Support for Authometion LYT8266 (testing, thanks to Joe Blellik, [#213](https://github.com/xoseperez/espurna/issues/213)) +- Support for an external button for D1 Mini boards (thanks to user @PieBru, [#239](https://github.com/xoseperez/espurna/issues/239)) - Option to query relay status via MQTT or WS (thanks to Wesley Tuzza) - Automatically install dependencies for web interface builder (thanks to Hermann Kraus) - Support for HSV and IR for Magic Home LED Controller (optional, disabled by default, thanks to Wesley Tuzza) - Added option to report DS18B20 temperatures based on changes (thanks to Michael A. Cox) - Safer buffer handling for websocket data (thanks to Hermann Kraus & Björn Bergman) - Updates HL8012 library with energy counting support (thanks to Hermann Kraus) -- Added option to disable light color persistence to avoid flickering (#191) -- Option to enable TELNET in STA mode from web UI (#203) +- Added option to disable light color persistence to avoid flickering ([#191](https://github.com/xoseperez/espurna/issues/191)) +- Option to enable TELNET in STA mode from web UI ([#203](https://github.com/xoseperez/espurna/issues/203)) ### Changed -- Changed default MQTT base topic to "{identifier}" (no leading slashes, #208) -- Prevent reconnecting when in AP mode if a web session or a telnet session is active (#244) -- Web UI checks for pending changes before reset/reconnect options (#226) +- Changed default MQTT base topic to "{identifier}" (no leading slashes, [#208](https://github.com/xoseperez/espurna/issues/208)) +- Prevent reconnecting when in AP mode if a web session or a telnet session is active ([#244](https://github.com/xoseperez/espurna/issues/244)) +- Web UI checks for pending changes before reset/reconnect options ([#226](https://github.com/xoseperez/espurna/issues/226)) - Increase WIFI connect timeout and reconnect interval ## [1.9.5] 2017-09-28 ### Fixed -- Revert to JustWifi 1.1.4 (#228) +- Revert to JustWifi 1.1.4 ([#228](https://github.com/xoseperez/espurna/issues/228)) ## [1.9.4] 2017-09-22 ### Added @@ -200,14 +452,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Support for powermeters based on ECH1560 IC (beta, untested) ### Changed -- Changed behaviour on MQTT connection failure (#215) +- Changed behaviour on MQTT connection failure ([#215](https://github.com/xoseperez/espurna/issues/215)) - Removed boot delay - Refactor power modules - Updated JustWifi library ### Fixed -- Set all esp8285 devices to use esp01_1m (#210, #225) -- Removed wifi gain option since it prevents some devices to connect (#204) +- Set all esp8285 devices to use esp01_1m ([#210](https://github.com/xoseperez/espurna/issues/210), [#225](https://github.com/xoseperez/espurna/issues/225)) +- Removed wifi gain option since it prevents some devices to connect ([#204](https://github.com/xoseperez/espurna/issues/204)) ## [1.9.3] 2017-09-04 ### Added @@ -220,13 +472,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Updated fauxmoESP library to 2.2.0 ### Fixed -- Fix HLW8012 calibration (#194) +- Fix HLW8012 calibration ([#194](https://github.com/xoseperez/espurna/issues/194)) - Fix telnet dropping connection -- Fix WiFiSecureClient connection with PubSubClient (#64) +- Fix WiFiSecureClient connection with PubSubClient ([#64](https://github.com/xoseperez/espurna/issues/64)) ## [1.9.2] 2017-08-31 ### Added -- System stability check (turns off everything except WIFI AP, OTA and telnet if there is a boot crash loop) (#196) +- System stability check (turns off everything except WIFI AP, OTA and telnet if there is a boot crash loop) ([#196](https://github.com/xoseperez/espurna/issues/196)) - Telnet support (enabled by default only on AP interface) - Option to set WiFi gain from web UI - Option to disable MQTT from web UI @@ -241,7 +493,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Changes in terminal commands ("reconnect" is now "reset.wifi", also new commands added) ### Fixed -- Crash in settings saving (#190) and fixed UDP debug conditional build clauses +- Crash in settings saving ([#190](https://github.com/xoseperez/espurna/issues/190)) and fixed UDP debug conditional build clauses ## [1.9.1] 2017-08-27 ### Added @@ -255,44 +507,44 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fixed build flags for DHT and DS18B20 in platformio.ini file - Fixed Itead Sonoff B1 by updating the my9291 library -- Fixed light status on boot (#157) +- Fixed light status on boot ([#157](https://github.com/xoseperez/espurna/issues/157)) - Fixed CSS bug cause by a bad merge ## [1.9.0] 2017-08-25 ### Added -- Support for IteadStudio BN-SZ01 Ceiling Light (#132) -- Support for IteadStudio Sonoff RF Bridge (#173) -- Support for IteadStudio Sonoff 4CH Pro (#174) +- Support for IteadStudio BN-SZ01 Ceiling Light ([#132](https://github.com/xoseperez/espurna/issues/132)) +- Support for IteadStudio Sonoff RF Bridge ([#173](https://github.com/xoseperez/espurna/issues/173)) +- Support for IteadStudio Sonoff 4CH Pro ([#174](https://github.com/xoseperez/espurna/issues/174)) - Support for IteadStudio Sonoff B1 - Support for IteadStudio Sonoff LED - Support for IteadStudio Sonoff T1 wall switches (1, 2 and 4 channels) - Support for WiOn 50055 WiFi Wall Outlet & Tap -- Support for EXS WiFi Relay v3.1 (and other future latching relay boards) (#152) -- TLS/SSL support for MQTT (caution: eats a lot of memory, do not use with web interface) (#64) -- Add support for delayed ON/OFF switches (#123, #161, #188) -- Added ON and OFF actions for button events (previously only TOGGLE available) (#182) +- Support for EXS WiFi Relay v3.1 (and other future latching relay boards) ([#152](https://github.com/xoseperez/espurna/issues/152)) +- TLS/SSL support for MQTT (caution: eats a lot of memory, do not use with web interface) ([#64](https://github.com/xoseperez/espurna/issues/64)) +- Add support for delayed ON/OFF switches ([#123](https://github.com/xoseperez/espurna/issues/123), [#161](https://github.com/xoseperez/espurna/issues/161), [#188](https://github.com/xoseperez/espurna/issues/188)) +- Added ON and OFF actions for button events (previously only TOGGLE available) ([#182](https://github.com/xoseperez/espurna/issues/182)) - Sliders in web interface to control dimmer channels independently (also for brightness) - Debug info about MQTT disconnect reason ### Changed - MQTT setters ending with "/set" by default -- Using DOUT flash mode on all devices (#167) +- Using DOUT flash mode on all devices ([#167](https://github.com/xoseperez/espurna/issues/167)) - Longer timeout for WiFi connection (better chances for Sonoff Basic to connect) -- Changed MQTT topics for light devices (COLOR, BRIGHTNESS, MIRED, KELVIN, CHANNEL) (#144) +- Changed MQTT topics for light devices (COLOR, BRIGHTNESS, MIRED, KELVIN, CHANNEL) ([#144](https://github.com/xoseperez/espurna/issues/144)) - Changed the way light devices are defined (see LIGHT_PROVIDER_DIMMER) - Allow to disable color picker in web interface -- API returns processed values for HLW8012 sensor (not raw values anymore) (#176) +- API returns processed values for HLW8012 sensor (not raw values anymore) ([#176](https://github.com/xoseperez/espurna/issues/176)) - Major refactoring of settings ### Fixed -- Discard MQTT messages with empty payload (#185) +- Discard MQTT messages with empty payload ([#185](https://github.com/xoseperez/espurna/issues/185)) - Wifi connection issue (https://github.com/esp8266/Arduino/issues/2186) - Alexa connection issue ## [1.8.3] 2017-07-23 ### Added -- Issue #85 and #90. Option to report MQTT messages with JSON payloads -- Issue #170. Updated DebouceEvent library to allow disabling double click and get faster click responses +- Issue [#85](https://github.com/xoseperez/espurna/issues/85) and [#90](https://github.com/xoseperez/espurna/issues/90). Option to report MQTT messages with JSON payloads +- Issue [#170](https://github.com/xoseperez/espurna/issues/170). Updated DebouceEvent library to allow disabling double click and get faster click responses - Using memory layout with no SPIFFS for 1Mb devices ### Changed @@ -300,8 +552,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Return times in ISO8601 format ### Fixed -- Issue #168. Added H801 to arduino.h file -- Issue #171. Fix corrupted will message +- Issue [#168](https://github.com/xoseperez/espurna/issues/168). Added H801 to arduino.h file +- Issue [#171](https://github.com/xoseperez/espurna/issues/171). Fix corrupted will message ## [1.8.2] 2017-07-16 ### Added @@ -310,45 +562,45 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Enable WIFI debug on hardware reset (button long click) ### Changed -- Issue #159. Allow decimals in relay pulse interval +- Issue [#159](https://github.com/xoseperez/espurna/issues/159). Allow decimals in relay pulse interval - Updated HLW8012 library ### Fixed -- Issue #148. Fix bug in conditional compilation check -- Issue #149. Using different pulse counters for each relay (thanks to Lauris Ieviņš) -- Issue #141. Limit relay pulse interval to 60s +- Issue [#148](https://github.com/xoseperez/espurna/issues/148). Fix bug in conditional compilation check +- Issue [#149](https://github.com/xoseperez/espurna/issues/149). Using different pulse counters for each relay (thanks to Lauris Ieviņš) +- Issue [#141](https://github.com/xoseperez/espurna/issues/141). Limit relay pulse interval to 60s - Fixed units for apparent & reactive power (thanks to Lauris Ieviņš) - Fixed mDNS setup when using custom HTTP port for web interface ## [1.8.1] 2017-05-22 ### Fixed -- Issue #140. Fix no relay control bug in Sonoff Dual +- Issue [#140](https://github.com/xoseperez/espurna/issues/140). Fix no relay control bug in Sonoff Dual ## [1.8.0] 2017-05-21 ### Added - Added gamma correction to RGB strips. Thanks to Chris Ward. - Added support for Huacanxing H801 WiFi LED Controller. Thanks to Minh Phuong Ly. -- Issue #138. Added NTP configuration from web interface -- Issue #128. Report color when booting and in heartbeat stream. -- Issue #126. Show NTP status in web interface. +- Issue [#138](https://github.com/xoseperez/espurna/issues/138). Added NTP configuration from web interface +- Issue [#128](https://github.com/xoseperez/espurna/issues/128). Report color when booting and in heartbeat stream. +- Issue [#126](https://github.com/xoseperez/espurna/issues/126). Show NTP status in web interface. - Added filter limits on POW readings. - Added color temperature to RGB calculation. Thanks to Sacha Telgenhof. -- Issue #120. Added relay flood protection. Thanks to Izik Dubnov. +- Issue [#120](https://github.com/xoseperez/espurna/issues/120). Added relay flood protection. Thanks to Izik Dubnov. - Support for "#RRGGBB", "RRR,GGG,BBB" and "WWW" color formats. -- Issue #117. Added build date & time to web interface. +- Issue [#117](https://github.com/xoseperez/espurna/issues/117). Added build date & time to web interface. ### Fixed - Fix MQTT_RELAY board conifugration. Thanks to Denis French. -- Issue #125. Fix bug in relay status reading from EEPROM -- Issue #127. Fix button action in DUAL. +- Issue [#125](https://github.com/xoseperez/espurna/issues/125). Fix bug in relay status reading from EEPROM +- Issue [#127](https://github.com/xoseperez/espurna/issues/127). Fix button action in DUAL. - Fix bug in Sonoff POW current reading. Thanks to Emmanuel Tatto. - Minimizing my9291 flickering when booting. - Fix conditional flags in hardware.ino to support Arduino IDE. ## [1.7.1] 2017-03-28 ### Fixed -- Issue #113. Fix restoring color from EEPROM upon reboot -- Issue #113. Fix bug in API handlers +- Issue [#113](https://github.com/xoseperez/espurna/issues/113). Fix restoring color from EEPROM upon reboot +- Issue [#113](https://github.com/xoseperez/espurna/issues/113). Fix bug in API handlers ## [1.7.0] 2017-03-27 ### Added @@ -367,10 +619,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Prevent the SDK from saving WiFi configuration to flash ### Fixed -- Issue #113. Fix light bulb state to OFF in library prevented the bulb from turning on -- Issue #58. Added code to handle spurious readings +- Issue [#113](https://github.com/xoseperez/espurna/issues/113). Fix light bulb state to OFF in library prevented the bulb from turning on +- Issue [#58](https://github.com/xoseperez/espurna/issues/58). Added code to handle spurious readings - Fix bug in HLW8012 calibration current parameter casting to int instead of float -- Issue #115. Removed local declaration of _mqttForward variable. Thanks to Paweł Fiedor +- Issue [#115](https://github.com/xoseperez/espurna/issues/115). Removed local declaration of _mqttForward variable. Thanks to Paweł Fiedor - Fix MQTT will topic. Thanks to Asbjorn Tronhus ## [1.6.9] 2017-03-12 @@ -387,27 +639,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.6.8] 2017-03-01 ### Added -- Issue #85. Heartbeat reports now free heap, uptime and VCC every 5 minutes +- Issue [#85](https://github.com/xoseperez/espurna/issues/85). Heartbeat reports now free heap, uptime and VCC every 5 minutes ### Changed - Wait two minutes instead of one in AP mode before trying to reconnect to the router -- Issue #92. Debug log enabled by default in Arduino IDE -- Issue #91. Using AsyncMqttClient as default MQTT client again +- Issue [#92](https://github.com/xoseperez/espurna/issues/92). Debug log enabled by default in Arduino IDE +- Issue [#91](https://github.com/xoseperez/espurna/issues/91). Using AsyncMqttClient as default MQTT client again ### Fixed - Report data from all sensors via websocket even if no MQTT connection -- Issue #92. Fix unknown reference in Arduino IDE +- Issue [#92](https://github.com/xoseperez/espurna/issues/92). Fix unknown reference in Arduino IDE - Split data.h contents into 1k lines, otherwise Arduino IDE chokes on them - Discard empty MQTT topic while subscribing ## [1.6.7] 2017-02-25 ### Added - Support for OpenLight / AI-Light by AI-Thinker based on MY9291 LED driver -- Issue #87. Factory reset when physical button pressed for >10 seconds +- Issue [#87](https://github.com/xoseperez/espurna/issues/87). Factory reset when physical button pressed for >10 seconds ## [1.6.6] 2017-02-23 ### Fixed -- Issue #82. Fix critical bug on Sonoff Dual +- Issue [#82](https://github.com/xoseperez/espurna/issues/82). Fix critical bug on Sonoff Dual ## [1.6.5] 2017-02-22 ### Added @@ -419,8 +671,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Double & long clicks do nothing except for the first defined button ### Fixed -- Issue #79. Fix bug in WiFi led notification & MQTT connectivity (using PubSubClient) -- Issue #73. Fix bug when building without Domoticz support +- Issue [#79](https://github.com/xoseperez/espurna/issues/79). Fix bug in WiFi led notification & MQTT connectivity (using PubSubClient) +- Issue [#73](https://github.com/xoseperez/espurna/issues/73). Fix bug when building without Domoticz support - Fix Gulp tasks dependencies ## [1.6.4] 2017-02-20 @@ -430,8 +682,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Support for PROGMEM debug messages (only wifi module has been changed) - Option to disable mDNS, enabled by default - Show current web server port in debug log -- Issue #75. Link relays to LEDs -- Issue #76. Using http://espurna.local when in AP mode +- Issue [#75](https://github.com/xoseperez/espurna/issues/75). Link relays to LEDs +- Issue [#76](https://github.com/xoseperez/espurna/issues/76). Using http://espurna.local when in AP mode ### Changed - Images and favicon is now embedded in the HTML @@ -441,16 +693,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Memory leak in MQTT connection method - Wait 60 seconds before retrying to connect when in AP mode -- Issue #24 & #74. Update ESPAsyncTCP and ESPAsyncWebServer to latest GIT version that supports MSS defragmenting -- Issue #73. Fixes for windows machines +- Issue [#24](https://github.com/xoseperez/espurna/issues/24) & [#74](https://github.com/xoseperez/espurna/issues/74). Update ESPAsyncTCP and ESPAsyncWebServer to latest GIT version that supports MSS defragmenting +- Issue [#73](https://github.com/xoseperez/espurna/issues/73). Fixes for windows machines ### Removed - Captive portal removed, mDNS resolution for AP mode too ## [1.6.3] 2017-02-15 ### Added -- Issue #69. Temperature unit configuration from the web interface -- Issue #55. WebServer port configurable from the web interface, defaults to 80 +- Issue [#69](https://github.com/xoseperez/espurna/issues/69). Temperature unit configuration from the web interface +- Issue [#55](https://github.com/xoseperez/espurna/issues/55). WebServer port configurable from the web interface, defaults to 80 - Expand network configuration when adding a new network ### Changed @@ -459,7 +711,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Scan for strongest network only if more than 1 network configured ### Fixed -- Issue #71. Added default values for netmask and DNS in web configuration +- Issue [#71](https://github.com/xoseperez/espurna/issues/71). Added default values for netmask and DNS in web configuration - Fixed Itead 1CH self-locking/inching board definition - Fixed PlatformIO environments for ESP8285 boards (4CH and Touch) @@ -491,11 +743,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.5.4] 2017-02-03 ### Fixed -- Issue #50. Fix type bug in window variable when calculating energy for HLW8012 devices (Sonoff POW) +- Issue [#50](https://github.com/xoseperez/espurna/issues/50). Fix type bug in window variable when calculating energy for HLW8012 devices (Sonoff POW) ## [1.5.3] 2017-02-02 ### Fixed -- Issue #50 and #54. Fixed domoticz MQTT message format +- Issue [#50](https://github.com/xoseperez/espurna/issues/50) and [#54](https://github.com/xoseperez/espurna/issues/54). Fixed domoticz MQTT message format ### Added - Energy calculation and aggregation. API entry points and MQTT messages. @@ -528,9 +780,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - MQTT will topic - Crash with HLW812 interrupts while trying to create a WIFI connection -- Issue #20 Better inline documentation for Alexa and Domoticz default settings -- Issue #39 Fixed autoconnect issue with static IP (fixed in JustWifi library) -- Issue #41 Added password requirements to initial password change page +- Issue [#20](https://github.com/xoseperez/espurna/issues/20) Better inline documentation for Alexa and Domoticz default settings +- Issue [#39](https://github.com/xoseperez/espurna/issues/39) Fixed autoconnect issue with static IP (fixed in JustWifi library) +- Issue [#41](https://github.com/xoseperez/espurna/issues/41) Added password requirements to initial password change page ### Changed - Changed LED pattern for WIFI notifications (shorter pulses) @@ -540,7 +792,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Adding current, voltage, apparent and reactive power reports to Sonoff POW (Web & MQTT) ### Fixed -- Issue #35 Fixed frequent MQTT connection drops after WIFI reconnect +- Issue [#35](https://github.com/xoseperez/espurna/issues/35) Fixed frequent MQTT connection drops after WIFI reconnect - Defer wifi disconnection from web interface to allow request to return ### Changed @@ -549,14 +801,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.4.3] 2017-01-11 ### Fixed -- Issue #6 Using forked Time library to prevent conflict with Arduino Core for ESP8266 time.h file in windows machines +- Issue [#6](https://github.com/xoseperez/espurna/issues/6) Using forked Time library to prevent conflict with Arduino Core for ESP8266 time.h file in windows machines ## [1.4.2] 2017-01-09 ### Added - Support for inverse logic relays ### Fixed -- Issue #31. Fixed error in relay identification from MQTT messages +- Issue [#31](https://github.com/xoseperez/espurna/issues/31). Fixed error in relay identification from MQTT messages ## [1.4.1] 2017-01-05 ### Added @@ -572,7 +824,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Support for static IP connections ### Fixed -- Issue #16. Enforce minimum password strength in web interface +- Issue [#16](https://github.com/xoseperez/espurna/issues/16). Enforce minimum password strength in web interface ### Changed - Using default client_id provided by AsyncMqttClient @@ -609,9 +861,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Skipping retained MQTT messages (configurable) ### Fixed -- Issue #11 Compile error when building sonoff-dual-debug -- Issue #14 MQTT Connection with Username an Password not working -- Issue #17 Moved static variable 'pending' to class variable +- Issue [#11](https://github.com/xoseperez/espurna/issues/11) Compile error when building sonoff-dual-debug +- Issue [#14](https://github.com/xoseperez/espurna/issues/14) MQTT Connection with Username an Password not working +- Issue [#17](https://github.com/xoseperez/espurna/issues/17) Moved static variable 'pending' to class variable ## [1.1.0] 2016-12-06 ### Added diff --git a/README.md b/README.md index 804c8065..08255855 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,38 @@ # ESPurna Firmware -ESPurna ("spark" in Catalan) is a custom firmware for ESP8266 based smart switches. -It was originally developed with the **[IteadStudio Sonoff](https://www.itead.cc/sonoff-wifi-wireless-switch.html)** in mind but now it supports a growing number of ESP8266-based boards. +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. -> **Current Release Version is 1.11.2**, read the [changelog](https://bitbucket.org/xoseperez/espurna/src/master/CHANGELOG.md). +[![version](https://img.shields.io/badge/version-1.13.0c-brightgreen.svg)](CHANGELOG.md) +[![branch](https://img.shields.io/badge/branch-fastled-orange.svg)](https://github.org/xoseperez/espurna/tree/fastled/) +[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=fastled)](https://travis-ci.org/xoseperez/espurna) +[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/fastled.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard) +[![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE) +
+[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest) +[![gitter](https://img.shields.io/gitter/room/tinkermant-cat/espurna.svg)](https://gitter.im/tinkerman-cat/espurna) +[![twitter](https://img.shields.io/twitter/follow/xoseperez.svg?style=social)](https://twitter.com/intent/follow?screen_name=xoseperez) -> **NOTICE**: Default flash layout changed in 1.8.3, as an unpredicted consequence devices will not be able to persist/retrieve configuration if flashed with 1.8.3 via **OTA** from **PlatformIO**. Please check issue #187. +--- -> **NOTICE**: since version 1.9.0 the default **MQTT topics for commands have changed**. They all now end with "/set". This means you will have to change your controller software (Node-RED or alike) to send messages to -for instance- "/home/living/light/relay/0/set". The device will publish its state in "/home/living/light/relay/0" like before. +## Notice + +> Please use the [gitter ESPurna channel](https://gitter.im/tinkerman-cat/espurna) for support and questions, you have better chances to get fast answers from me or other ESPurna users. Open an issue here only if you feel there is a bug or you want to request an enhancement. Thank you. ## Features -* *KRACK* vulnerability free (when built against Arduino Core 2.4.0 RC2) -* Support for **multiple ESP8266-based boards** ([check list](https://bitbucket.org/xoseperez/espurna/wiki/Hardware)) +* *KRACK* vulnerability free (when built with Arduino Core >= 2.4.0) +* Support for **multiple ESP8266-based boards** ([check list](https://github.com/xoseperez/espurna/wiki/Hardware)) * Power saving options * Wifi **AP Mode** or **STA mode** - * Up to 5 different networks can be defined * Supports static IP - * Scans for strongest network if more than one defined + * Up to 5 different networks can be defined + * Scans for strongest network if more than one defined (also available in web UI) + * Handles correctly multiple AP with the same SSID * Defaults to AP mode (also available after double clicking the main button) * Network visibility - * Supports mDNS (service reporting and metadata) - * Supports NetBIOS, LLMNR and Netbios (when built against Arduino Core 2.4.0 RC2) and SSDP (experimental) + * Supports mDNS (service reporting and metadata) both server mode and client mode (.local name resolution) + * Supports NetBIOS, LLMNR and Netbios (when built with Arduino Core >= 2.4.0) and SSDP (experimental) * Switch management * Support for **push buttons** and **toggle switches** * Configurable **status on boot** per switch (always ON, always OFF, same as before or toggle) @@ -31,44 +41,62 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari * Support for **MQTT groups** to sync switches between devices * Support for **delayed ON/OFF** * **MQTT** enabled - * **SSL/TLS support** (not on regular builds, see #64) + * **SSL/TLS support** (not on regular builds, see [#64](https://github.com/xoseperez/espurna/issues/64)) * Switch on/off and toggle relays, group topics (sync relays between different devices) * Report button event notifications * Enable/disable pulse mode * Change LED notification mode * Remote reset the board + * Fully configurable in webUI (broker, user, password, QoS, keep alive time, retain flag, client ID) +* **Scheduler** to automatically turn on, off or toggle any relay at a given time and day, also change light intensity for dimmers * **Alexa** integration using the [FauxmoESP Library](https://bitbucket.org/xoseperez/fauxmoesp) * [**Google Assistant**](http://tinkerman.cat/using-google-assistant-control-your-esp8266-devices/) integration using IFTTT and Webhooks (Google Home, Allo) * [**Domoticz**](https://domoticz.com/) integration via MQTT -* [**Home Assistant**](https://home-assistant.io/) integration via MQTT +* [**Home Assistant**](https://home-assistant.io/) integration * Support for switches (on/off) * Support for lights (color, brightness, on/off state) - * Supports MQTT auto-discover feature (both switches and lights) + * Supports MQTT auto-discover feature (switches, lights and sensors) + * Integration via MQTT Discover or copy-pasting configuration code * [**InfluxDB**](https://www.influxdata.com/) integration via HTTP API -* Support for different **sensors** +* [**Thingspeak**](https://thingspeak.com/) integration via HTTP API (HTTPS available for custom builds) +* **Sonoff RF Bridge** support + * Multiple virtual switches (tested with up to 16) + * MQTT-to-RF two-way bridge (no need to learn codes) + * Support for [https://github.com/Portisch/RF-Bridge-EFM8BB1](https://github.com/Portisch/RF-Bridge-EFM8BB1) custom firmware + * Support for [direct control of the encoder/decoder bypassing the EFM8BB1](https://github.com/xoseperez/espurna/wiki/Hardware-Itead-Sonoff-RF-Bridge---Direct-Hack) +* Support for [different **sensors**](Sensors) * Environment - * **DHT11 / DHT22 / DHT21 / AM2301 / Itead's SI7021** (supports celsius & fahrenheit reporting) + * **DHT11 / DHT22 / DHT21 / AM2301 / Itead's SI7021** * **BMP280** and **BME280** temperature, humidity (BME280) and pressure sensor by Bosch * **SI7021** temperature and humidity sensor - * **SHT2X** temperature and humidity sensor over I2C (Wemos shield) - * **Dallas OneWire sensors** like the DS18B20 (supports celsius & fahrenheit reporting) + * **SHT3X** temperature and humidity sensor over I2C (Wemos shield) + * **AM2320** temperature and humidity sensor over I2C + * **Dallas OneWire sensors** like the DS18B20 * **MHZ19** CO2 sensor - * **PMSX003** dust sensor + * **SenseAir S8** CO2 sensor + * **PMSX003/PMS5003T/ST** dust sensors * **BH1750** luminosity sensor + * **GUVAS12SD** UV sensor * Power monitoring * **HLW8012** using the [HLW8012 Library](https://bitbucket.org/xoseperez/hlw8012) (Sonoff POW) * Non-invasive **current sensor** using **internal ADC** or **ADC121** or **ADS1115** * **ECH1560** power monitor chip * **V9261F** power monitor chip + * **PZEM0004T** power monitor board * Raw analog and digital sensors * Simple pulse counter + * Support for different units (Fahrenheit or Celsius, Watts or Kilowatts, Joules or kWh) * Support for LED lights * MY92XX-based light bulbs and PWM LED strips (dimmers) up to 5 channels (RGB, cold white and warm white, for instance) * RGB and HSV color codes supported * Manage channels individually - * Temperature color supported (in mired and kelvin) via MQTT / REST API + * Temperature color supported (in [mired](https://en.wikipedia.org/wiki/Mired) and [kelvin](https://en.wikipedia.org/wiki/Color_temperature)) via MQTT / REST API * Flicker-free PWM management * Soft color transitions + * Color synchronization between light using MQTT + * Option to have separate switches for each channel +* Support for simple 433MHz RF receivers +* Support for UART-to-MQTT bidirectional bridge * Fast asynchronous **HTTP Server** * Configurable port * Basic authentication @@ -95,10 +123,14 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari * Run special commands * **Telnet support** * Enable/disable via the web UI - * Show debug info and allows to run terminal commands + * Shows debug info and allows to run terminal commands +* **NTP** for time synchronization + * Supports worldwide time zones + * Compatible with DST (EU and USA) * **Unstable system check** * Detects unstable system (crashes on boot continuously) and defaults to a stable system * Only WiFi AP, OTA and Telnet available if system is flagged as unstable +* Configurable LED notifications based on WiFi status, relays status or MQTT messages. * Button interface * Click to toggle relays * Double click to enter AP mode (only main button) @@ -106,44 +138,123 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari * Extra long click (>10 seconds) to go back to factory settings (only main button) * Specific definitions for touch button devices (ESPurna Switch, Sonoff Touch & T1) +## Notices + +--- +> **2018-04-08**
+> Please use [gitter](https://gitter.im/tinkerman-cat/espurna) for support and questions, you have better chances to get fast answers by me or other ESPurna users. Open an issue here only if you feel there is a bug or you want to request an enhancement. Thank you. + +--- +> **2018-03-09**
+> Default branch in GitHub is now the development branch "dev".
+> The stable branch (the one used to create the [binary releases](https://github.com/xoseperez/espurna/releases)) is "[master](https://github.com/xoseperez/espurna/tree/master)". + +--- +> **2018-01-24**
+> This repository has been migrated from Bitbucket to GitHub. There were a number of reason to migrate the repository to GitHub. I like Bitbucket and I'm still using it for a lot of projects, but ESPurna has grown and its community as well. Some users have complain about Bitbucket not being enough community-focused. This change is mainly aimed to use a platform with greater acceptance on the open-source community and tools better suited to them (to you), like the possibility to contribute to the documentation in an easy way. +> +>What happened with all the info in Bitbucket? Well, most of it has been ported to GitHub, albeit with some quirks: +> +>* **Code** has, of course been migrated completely +>* **Issues** are all on GitHub already **but** all issues and comments show up as reported by me. The original reporter is referenced inside the body of the issue (or comment) with a link to his/her profile at Bitbucket and a link to his/her profile at GitHub if it happens to be the same username. I **suggest all reporters to subscribe to the issues they originally filed** (search for your BitBucket username to list them). +>* **Pull requests** historic has not been migrated. At the moment of the migration all pull-requests have been either merged or declined. Of course, those PR merged are in the code base, but the historic and comments in the PR pages will be lost. +>* **Documentation** it's on it way, first step will be to migrate existing wiki, maybe with a new TOC structure +>* **Watchers**, **Forks**, I'm afraid they are all gone. Visit the new repo home and click on the "Watch" button on the top right. And as you do it click also on the "Star" button too :) +> +>I apologize for any inconvenience this migration may have caused. I have decided to do it the hard way. + +--- +> **2018-01-11**
+> As of current version (1.12.0) ESPurna is tested using Arduino Core 2.3.0 and it's meant to be built against that version. + +--- +> **2017-08-26**
+> Since version 1.9.0 the default **MQTT topics for commands have changed**. They all now end with "/set". This means you will have to change your controller software (Node-RED or alike) to send messages to -for instance- "/home/living/light/relay/0/set". The device will publish its state in "/home/living/light/relay/0" like before. + +--- +> **2017-07-24**
+> Default flash layout changed in 1.8.3, as an unpredicted consequence devices will not be able to persist/retrieve configuration if flashed with 1.8.3 via **OTA** from **PlatformIO**. Please check issue [#187](https://github.com/xoseperez/espurna/issues/187). + +--- + +## Contribute + +There are several ways to contribute to ESPurna development. You can contribute to the repository by doing: + +* Pull requests (fixes, enhancements, new features... are very welcome) +* Documentation (I reckon I'm bad at it) +* Testing (filing issues or help resolving them, they take a lot of time and sometimes I don't have the required hardware to test them all) + +And of course you can always buy me a beer, coffee, tea,... via the donation button below. + +[![Donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest) + ## Documentation -For more information please refer to the [ESPurna Wiki](https://bitbucket.org/xoseperez/espurna/wiki/Home). +For more information please refer to the [ESPurna Wiki](https://github.com/xoseperez/espurna/wiki). ## Supported hardware -Here is the list of supported hardware. For more information please refer to the [ESPurna Wiki Hardware page](https://bitbucket.org/xoseperez/espurna/wiki/Hardware). +Here is the list of supported hardware. For more information please refer to the [ESPurna Wiki Hardware page](https://github.com/xoseperez/espurna/wiki/Hardware). |||| |---|---|---| -|![Tinkerman Espurna H](images/devices/tinkerman-espurna-h.jpg)|![IteadStudio Sonoff RF Bridge](images/devices/itead-sonoff-rfbridge.jpg)|| -|**Tinkerman ESPurna H**|**IteadStudio Sonoff RF Bridge**|| -|![IteadStudio Sonoff Basic](images/devices/itead-sonoff-basic.jpg)|![IteadStudio Sonoff RF](images/devices/itead-sonoff-rf.jpg)|![Electrodragon WiFi IOT](images/devices/electrodragon-wifi-iot.jpg)| -|**IteadStudio Sonoff Basic**|**IteadStudio Sonoff RF**|**Electrodragon WiFi IOT**| -|![IteadStudio Sonoff Dual](images/devices/itead-sonoff-dual.jpg)|![IteadStudio Sonoff POW](images/devices/itead-sonoff-pow.jpg)|![IteadStudio Sonoff TH10/TH16](images/devices/itead-sonoff-th.jpg)| -|**IteadStudio Sonoff Dual**|**IteadStudio Sonoff POW**|**IteadStudio Sonoff TH10/TH16**| -|![IteadStudio Sonoff 4CH](images/devices/itead-sonoff-4ch.jpg)|![IteadStudio Sonoff 4CH Pro](images/devices/itead-sonoff-4ch-pro.jpg)|![OpenEnergyMonitor WiFi MQTT Relay / Thermostat](images/devices/openenergymonitor-mqtt-relay.jpg)| -|**IteadStudio Sonoff 4CH**|**IteadStudio Sonoff 4CH Pro**|**OpenEnergyMonitor WiFi MQTT Relay / Thermostat**| -|![IteadStudio S20](images/devices/itead-s20.jpg)|![WorkChoice EcoPlug](images/devices/workchoice-ecoplug.jpg)|![Power meters based on V9261F and ECH1560](images/devices/generic-v9261f.jpg)| -|**IteadStudio S20**|**WorkChoice EcoPlug**|**Power meters based on V9261F and ECH1560**| -|![IteadStudio Sonoff Touch](images/devices/itead-sonoff-touch.jpg)|![IteadStudio Sonoff T1](images/devices/itead-sonoff-t1.jpg)|| -|**IteadStudio Sonoff Touch**|**IteadStudio Sonoff T1**|| -|![IteadStudio Slampher](images/devices/itead-slampher.jpg)|![AI-Thinker Wifi Light / Noduino OpenLight](images/devices/aithinker-ai-light.jpg)|![Itead Sonoff B1](images/devices/itead-sonoff-b1.jpg)| -|**IteadStudio Slampher**|**AI-Thinker Wifi Light / Noduino OpenLight**|**IteadStudio Sonoff B1**| -|![MagicHome LED Controller (1.0 and 2.0)](images/devices/magichome-led-controller.jpg)|![Huacanxing H801](images/devices/huacanxing-h801.jpg)|![Itead BN-SZ01](images/devices/itead-bn-sz01.jpg)| -|**MagicHome LED Controller (1.0 and 2.0)**|**Huacanxing H801**|**Itead BN-SZ01**| -|![IteadStudio Sonoff SV](images/devices/itead-sonoff-sv.jpg)|![IteadStudio 1CH Inching](images/devices/itead-1ch-inching.jpg)|![IteadStudio Motor Clockwise/Anticlockwise](images/devices/itead-motor.jpg)| -|**IteadStudio Sonoff SV**|**IteadStudio 1CH Inching**|**IteadStudio Motor Clockwise/Anticlockwise**| -|![Wemos D1 Mini Relay Shield](images/devices/wemos-d1-mini-relayshield.jpg)|![Jan Goedeke Wifi Relay (NO/NC)](images/devices/jangoe-wifi-relay.png)|![Jorge García Wifi + Relays Board Kit](images/devices/jorgegarcia-wifi-relays.jpg)| -|**Wemos D1 Mini Relay Shield**|**Jan Goedeke Wifi Relay (NO/NC)**|**Jorge García Wifi + Relays Board Kit**| -|![EXS Wifi Relay v3.1](images/devices/exs-wifi-relay-v31.jpg)||| -|**EXS Wifi Relay v3.1**||| - -**Other supported boards:** Itead Sonoff LED, Itead Sonoff Dual R2, Huacanxing H802, WiOn 50055, ManCaveMade ESP-Live, InterMitTech QuinLED 2.6, Arilux AL-LC01, Arilux AL-LC06, Arilux AL-LC11, Arilux E27 light bulb, Xenon SM-PW702U, Authometion LYT8266, YJZK 2-gang switch. +|![Tinkerman Espurna H](images/devices/tinkerman-espurna-h.jpg)||| +|**Tinkerman ESPurna H**||| +|![Itead Sonoff RF Bridge](images/devices/itead-sonoff-rfbridge.jpg)||| +|**Itead Sonoff RF Bridge**||| +|![Itead Sonoff Basic](images/devices/itead-sonoff-basic.jpg)|![Itead Sonoff RF](images/devices/itead-sonoff-rf.jpg)|![Itead Sonoff Dual/Dual R2](images/devices/itead-sonoff-dual.jpg)| +|**Itead Sonoff Basic**|**Itead Sonoff RF**|**Itead Sonoff Dual/Dual R2**| +|![Itead Sonoff POW](images/devices/itead-sonoff-pow.jpg)|![Itead Sonoff TH10/TH16](images/devices/itead-sonoff-th.jpg)|![Electrodragon WiFi IOT](images/devices/electrodragon-wifi-iot.jpg)| +|**Itead Sonoff POW**|**Itead Sonoff TH10/TH16**|**Electrodragon WiFi IOT**| +|![Itead Sonoff 4CH](images/devices/itead-sonoff-4ch.jpg)|![Itead Sonoff 4CH Pro](images/devices/itead-sonoff-4ch-pro.jpg)|![OpenEnergyMonitor WiFi MQTT Relay / Thermostat](images/devices/openenergymonitor-mqtt-relay.jpg)| +|**Itead Sonoff 4CH**|**Itead Sonoff 4CH Pro**|**OpenEnergyMonitor WiFi MQTT Relay / Thermostat**| +|![Itead S20](images/devices/itead-s20.jpg)|![WorkChoice EcoPlug](images/devices/workchoice-ecoplug.jpg)|![Power meters based on V9261F and ECH1560](images/devices/generic-v9261f.jpg)| +|**Itead S20**|**WorkChoice EcoPlug**|**Power meters based on V9261F and ECH1560**| +|![Schuko Wifi Plug](images/devices/schuko-wifi-plug.jpg)|![KMC 70011](images/devices/kmc-70011.jpg)|![Xenon SM-PW702U](images/devices/xenon-sm-pw702u.jpg)| +|**Schuko Wifi Plug**|**KMC 70011**|**Xenon SM-PW702U**| +|![Maxcio W-US002S](images/devices/maxcio-w-us002s.jpg)|![HEYGO HY02](images/devices/heygo-hy02.jpg)|![YiDian XS-SSA05](images/devices/yidian-xs-ssa05.jpg)| +|**Maxcio W-US002S**|**HEYGO HY02**|**YiDian XS-SSA05**| +|![WiOn 50055](images/devices/wion-50055.jpg)|![LINGAN SWA1](images/devices/lingan-swa1.jpg)|![Tonbux PowerStrip02](images/devices/tonbux-powerstrip02.jpg)| +|**WiOn 50055**|**LINGAN SWA1**|**Tonbux PowerStrip02** +|![Itead Sonoff Touch](images/devices/itead-sonoff-touch.jpg)|![Itead Sonoff T1](images/devices/itead-sonoff-t1.jpg)|![YJZK 2-gang switch](images/devices/yjzk-2gang-switch.jpg)| +|**Itead Sonoff Touch**|**Itead Sonoff T1**|**YJZK 2-gang switch**| +|![Itead Slampher](images/devices/itead-slampher.jpg)||| +|**Itead Slampher**||| +|![Itead Sonoff B1](images/devices/itead-sonoff-b1.jpg)|![AI-Thinker Wifi Light / Noduino OpenLight](images/devices/aithinker-ai-light.jpg)|![Authometion LYT8266](images/devices/authometion-lyt8266.jpg)| +|**Itead Sonoff B1**|**AI-Thinker Wifi Light / Noduino OpenLight**|**Authometion LYT8266**| +|![Arilux E27](images/devices/arilux-e27.jpg)|![Itead Sonoff LED](images/devices/itead-sonoff-led.jpg)|![Itead BN-SZ01](images/devices/itead-bn-sz01.jpg)| +|**Arilux E27**|**Itead Sonoff LED**|**Itead BN-SZ01**| +|![Arilux AL-LC01 (RGB)](images/devices/arilux-al-lc01.jpg)|![Arilux AL-LC02 (RGBW)](images/devices/arilux-al-lc02.jpg)|![Arilux AL-LC06 (RGBWWCW)](images/devices/arilux-al-lc06.jpg)| +|**Arilux AL-LC01 (RGB)**|**Arilux AL-LC02 (RGBW)**|**Arilux AL-LC06 (RGBWWCW)**| +|![Arilux AL-LC11 (RGBWWW) & RF](images/devices/arilux-al-lc11.jpg)|![MagicHome LED Controller (1.0 and 2.x)](images/devices/magichome-led-controller.jpg)|![Huacanxing H801/802](images/devices/huacanxing-h801.jpg)| +|**Arilux AL-LC11 (RGBWWW) & RF**|**MagicHome LED Controller (1.0/2.x)**|**Huacanxing H801/802**| +|![InterMitTech QuinLED 2.6](images/devices/intermittech-quinled-2.6.jpg)|| +|**InterMitTech QuinLED 2.6**|| +|![Itead Sonoff SV](images/devices/itead-sonoff-sv.jpg)|![Itead 1CH Inching](images/devices/itead-1ch-inching.jpg)|![Itead Motor Clockwise/Anticlockwise](images/devices/itead-motor.jpg)| +|**Itead Sonoff SV**|**Itead 1CH Inching**|**Itead Motor Clockwise/Anticlockwise**| +|![Jan Goedeke Wifi Relay (NO/NC)](images/devices/jangoe-wifi-relay.jpg)|![Jorge García Wifi + Relays Board Kit](images/devices/jorgegarcia-wifi-relays.jpg)|![EXS Wifi Relay v3.1](images/devices/exs-wifi-relay-v31.jpg)| +|**Jan Goedeke Wifi Relay (NO/NC)**|**Jorge García Wifi + Relays Board Kit**|**EXS Wifi Relay v3.1**| +|![ManCaveMade ESP-Live](images/devices/mancavemade-esp-live.jpg)|![Wemos D1 Mini Relay Shield](images/devices/wemos-d1-mini-relayshield.jpg)|![Witty Cloud](images/devices/witty-cloud.jpg)| +|**ManCaveMade ESP-Live**|**Wemos D1 Mini Relay Shield**|**Witty Cloud**| +|![IKE ESPike](images/devices/ike-espike.jpg)||![Arniex Swifitch](images/devices/arniex-swifitch.jpg)| +|**IKE ESPike**|**STM_RELAY**|**Arniex Swifitch**| +|![Heltec Touch Relay](images/devices/heltec-touch-relay.jpg)|![Generic Relay v4.0](images/devices/generic-relay-40.jpg)|![Generic RGBLed v1.0](images/devices/generic-rgbled-10.jpg)| +|**Heltec Touch Relay**|**Generic Relay v4.0**|**Generic RGBLed v1.0**| +|![Generic DHT11 v1.0](images/devices/generic-dht11-10.jpg)|![Generic DS18B20 v1.0](images/devices/generic-ds18b20-10.jpg)|| +|**Generic DHT11 v1.0**|**Generic DS18B20 v1.0**|| +|![Tonbux Mosquito Killer](images/devices/tonbux-mosquito-killer.jpg)||| +|**Tonbux Mosquito Killer**||| + +**Other supported boards:** +IteadStudio Sonoff S31, IteadStudio Sonoff POW R2, Zhilde ZLD-EU55-W, Luani HVIO + +**Other supported boards (beta):** +KMC 4 Outlet, Gosund WS1, Smart Dual Plug, MakerFocus Intelligent Module LM33 for Lamps ## License -Copyright (C) 2016-2017 by Xose Pérez (@xoseperez) +Copyright (C) 2016-2018 by Xose Pérez (@xoseperez) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/code/.gitignore b/code/.gitignore index a7e598ae..d88ad014 100644 --- a/code/.gitignore +++ b/code/.gitignore @@ -1,8 +1,13 @@ .clang_complete +core_version.h +custom.h +.DS_Store .gcc-flags.json .pioenvs .piolibdeps +.python-version +.travis.yml +.vscode +.vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json -core_version.h -.pioenvs -.piolibdeps +.vscode/launch.json diff --git a/code/.travis.yml b/code/.travis.yml deleted file mode 100644 index 86596a0c..00000000 --- a/code/.travis.yml +++ /dev/null @@ -1,65 +0,0 @@ -# Continuous Integration (CI) is the practice, in software -# engineering, of merging all developer working copies with a shared mainline -# several times a day < http://docs.platformio.org/en/latest/ci/index.html > -# -# Documentation: -# -# * Travis CI Embedded Builds with PlatformIO -# < https://docs.travis-ci.com/user/integration/platformio/ > -# -# * PlatformIO integration with Travis CI -# < http://docs.platformio.org/en/latest/ci/travis.html > -# -# * User Guide for `platformio ci` command -# < http://docs.platformio.org/en/latest/userguide/cmd_ci.html > -# -# -# Please choice one of the following templates (proposed below) and uncomment -# it (remove "# " before each line) or use own configuration according to the -# Travis CI documentation (see above). -# - - -# -# Template #1: General project. Test it using existing `platformio.ini`. -# - - language: python - python: - - "2.7" - - sudo: false - cache: - directories: - - "~/.platformio" - - install: - - pip install -U platformio - - script: - - platformio run - - -# -# Template #2: The project is intended to by used as a library with examples -# - -# language: python -# python: -# - "2.7" -# -# sudo: false -# cache: -# directories: -# - "~/.platformio" -# -# env: -# - PLATFORMIO_CI_SRC=path/to/test/file.c -# - PLATFORMIO_CI_SRC=examples/file.ino -# - PLATFORMIO_CI_SRC=path/to/test/directory -# -# install: -# - pip install -U platformio -# -# script: -# - platformio ci --lib="." --board=TYPE_1 --board=TYPE_2 --board=TYPE_N diff --git a/code/build.sh b/code/build.sh index de85f451..5b1fd86d 100755 --- a/code/build.sh +++ b/code/build.sh @@ -5,7 +5,10 @@ echo "--------------------------------------------------------------" echo "ESPURNA FIRMWARE BUILDER" # Available environments -available=`cat platformio.ini | grep env: | grep -v ota | grep -v ssl | sed 's/\[env://' | sed 's/\]/ /' | sort` +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) + +# Parameters environments=$@ if [ "$environments" == "list" ]; then echo "--------------------------------------------------------------" @@ -18,11 +21,21 @@ fi # Environments to build if [ $# -eq 0 ]; then + environments=$available + + # Hook to build travis test envs + if [[ "${TRAVIS_BRANCH}" != "" ]]; then + re='^[0-9]+\.[0-9]+\.[0-9]+$' + if ! [[ ${TRAVIS_BRANCH} =~ $re ]]; then + environments=$travis + fi + fi + fi # Get current version -version=`cat espurna/config/version.h | grep APP_VERSION | awk '{print $3}' | sed 's/"//g'` +version=$(grep APP_VERSION espurna/config/version.h | awk '{print $3}' | sed 's/"//g') echo "Building for version $version" # Create output folder @@ -34,18 +47,27 @@ if [ ! -e node_modules/gulp/bin/gulp.js ]; then npm install --only=dev fi +echo "--------------------------------------------------------------" +echo "Get revision..." +revision=$(git rev-parse HEAD) +revision=${revision:0:7} +cp espurna/config/version.h espurna/config/version.h.original +sed -i -e "s/APP_REVISION \".*\"/APP_REVISION \"$revision\"/g" espurna/config/version.h + # Recreate web interface echo "--------------------------------------------------------------" echo "Building web interface..." node node_modules/gulp/bin/gulp.js || exit -# Build all the required firmwares +# Build all the required firmware images echo "--------------------------------------------------------------" echo "Building firmware images..." -mkdir -p firmware/espurna-$version +mkdir -p ../firmware/espurna-$version for environment in $environments; do echo "* espurna-$version-$environment.bin" - platformio run -s -e $environment || exit - mv .pioenvs/$environment/firmware.bin firmware/espurna-$version/espurna-$version-$environment.bin + platformio run --silent --environment $environment || exit 1 + mv .pioenvs/$environment/firmware.bin ../firmware/espurna-$version/espurna-$version-$environment.bin done echo "--------------------------------------------------------------" + +mv espurna/config/version.h.original espurna/config/version.h diff --git a/code/core_version.py b/code/core_version.py deleted file mode 100644 index bffcb03a..00000000 --- a/code/core_version.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/python - -import json -import commands -import subprocess -import os -import sys - -def core_version(env): - - # Get the core folder - fwdir = env["FRAMEWORK_ARDUINOESP8266_DIR"] - - # Get the core version - with open(fwdir + '/package.json') as data_file: - data = json.load(data_file) - core_version = data["version"].upper().replace(".", "_").replace("-", "_") - print "CORE VERSION: %s" % core_version - - # Get git version - pr = subprocess.Popen( - "git --git-dir .git rev-parse --short=8 HEAD 2>/dev/null || echo ffffffff", - cwd = fwdir, - shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE ) - (out, error) = pr.communicate() - git_version = str(out).replace('\n', "") - print "GIT VERSION: %s" % git_version - - #env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_RELEASE=" + core_version) - #env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_RELEASE_" + core_version) - #env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_GIT_VER=" + git_version) - - with open('espurna/config/core_version.h', 'w') as the_file: - the_file.write('#define ARDUINO_ESP8266_RELEASE "%s"\n' % core_version) - the_file.write('#define ARDUINO_ESP8266_RELEASE_%s\n' % core_version) - the_file.write('#define ARDUINO_ESP8266_GIT_VER "%s"\n' % git_version) - - #env.Append( - # CFLAGS = [ - # str("-DARDUINO_ESP8266_RELEASE=" + core_version), - # str("-DARDUINO_ESP8266_RELEASE_" + core_version), - # str("-DARDUINO_ESP8266_GIT_VER=" + git_version) - # ] - #) - - #print " -DARDUINO_ESP8266_RELEASE=" + core_version + - # " -DARDUINO_ESP8266_RELEASE_" + core_version + - # " -DARDUINO_ESP8266_GIT_VER=" + git_version - -Import('env') -core_version(env) diff --git a/code/esp8266.flash.1m0.ld b/code/eagle.flash.1m0m1s.ld similarity index 75% rename from code/esp8266.flash.1m0.ld rename to code/eagle.flash.1m0m1s.ld index dbb44e94..36477dc8 100644 --- a/code/esp8266.flash.1m0.ld +++ b/code/eagle.flash.1m0m1s.ld @@ -1,4 +1,4 @@ -/* Flash Split for 1M chips, no SPIFFS */ +/* Flash Split for 1M chips */ /* sketch 999KB */ /* eeprom 20KB */ @@ -12,7 +12,7 @@ MEMORY PROVIDE ( _SPIFFS_start = 0x402FB000 ); PROVIDE ( _SPIFFS_end = 0x402FB000 ); -PROVIDE ( _SPIFFS_page = 0 ); -PROVIDE ( _SPIFFS_block = 0 ); +PROVIDE ( _SPIFFS_page = 0x0 ); +PROVIDE ( _SPIFFS_block = 0x0 ); -INCLUDE "esp8266.flash.common.ld" +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/code/eagle.flash.1m0m2s.ld b/code/eagle.flash.1m0m2s.ld new file mode 100644 index 00000000..bf07dccd --- /dev/null +++ b/code/eagle.flash.1m0m2s.ld @@ -0,0 +1,19 @@ +/* Flash Split for 1M chips, no SPIFFS */ +/* sketch 995KB */ +/* eeprom 8KB */ +/* reserved 16KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0xf8ff0 +} + +PROVIDE ( _SPIFFS_start = 0x402FA000 ); +PROVIDE ( _SPIFFS_end = 0x402FA000 ); +PROVIDE ( _SPIFFS_page = 0 ); +PROVIDE ( _SPIFFS_block = 0 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/code/eagle.flash.4m1m4s.ld b/code/eagle.flash.4m1m4s.ld new file mode 100644 index 00000000..696adcdc --- /dev/null +++ b/code/eagle.flash.4m1m4s.ld @@ -0,0 +1,21 @@ +/* Flash Split for 4M chips */ +/* sketch 1019KB */ +/* empty/ota? 2048KB */ +/* spiffs 992KB */ +/* eeprom 16KB */ +/* reserved 16KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0xfeff0 +} + +PROVIDE ( _SPIFFS_start = 0x40500000 ); +PROVIDE ( _SPIFFS_end = 0x405F8000 ); +PROVIDE ( _SPIFFS_page = 0x100 ); +PROVIDE ( _SPIFFS_block = 0x2000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/code/eagle.flash.4m3m4e.ld b/code/eagle.flash.4m3m4e.ld new file mode 100644 index 00000000..6470d827 --- /dev/null +++ b/code/eagle.flash.4m3m4e.ld @@ -0,0 +1,20 @@ +/* Flash Split for 4M chips */ +/* sketch 1019KB */ +/* spiffs 3040KB */ +/* eeprom 16KB */ +/* reserved 16KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0xfeff0 +} + +PROVIDE ( _SPIFFS_start = 0x40300000 ); +PROVIDE ( _SPIFFS_end = 0x405F8000 ); +PROVIDE ( _SPIFFS_page = 0x100 ); +PROVIDE ( _SPIFFS_block = 0x2000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/code/eagle.flash.512k0m1s.ld b/code/eagle.flash.512k0m1s.ld new file mode 100644 index 00000000..e28fc9f1 --- /dev/null +++ b/code/eagle.flash.512k0m1s.ld @@ -0,0 +1,18 @@ +/* Flash Split for 512K chips */ +/* sketch 487KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0x79ff0 +} + +PROVIDE ( _SPIFFS_start = 0x4027B000 ); +PROVIDE ( _SPIFFS_end = 0x4027B000 ); +PROVIDE ( _SPIFFS_page = 0x0 ); +PROVIDE ( _SPIFFS_block = 0x0 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/code/espurna/alexa.ino b/code/espurna/alexa.ino index cfbdf25b..81815d8b 100644 --- a/code/espurna/alexa.ino +++ b/code/espurna/alexa.ino @@ -2,23 +2,30 @@ ALEXA MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ #if ALEXA_SUPPORT #include - fauxmoESP alexa; +struct AlexaDevChange { + AlexaDevChange(unsigned char device_id, bool state) : device_id(device_id), state(state) {}; + unsigned char device_id = 0; + bool state = false; +}; +#include +static std::queue _alexa_dev_changes; + // ----------------------------------------------------------------------------- // ALEXA // ----------------------------------------------------------------------------- -bool _alexa_change = false; -unsigned int _alexa_device_id = 0; -bool _alexa_state = false; +bool _alexaWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "alexa", 5) == 0); +} void _alexaWebSocketOnSend(JsonObject& root) { root["alexaVisible"] = 1; @@ -44,6 +51,7 @@ void alexaSetup() { // Websockets wsOnSendRegister(_alexaWebSocketOnSend); wsOnAfterParseRegister(_alexaConfigure); + wsOnReceiveRegister(_alexaWebSocketOnReceive); #endif @@ -57,26 +65,29 @@ void alexaSetup() { } } - alexa.onSetState([relays](unsigned char device_id, const char * name, bool state) { - _alexa_change = true; - _alexa_device_id = device_id; - _alexa_state = state; + alexa.onSetState([&](unsigned char device_id, const char * name, bool state) { + AlexaDevChange change(device_id, state); + _alexa_dev_changes.push(change); }); - alexa.onGetState([relays](unsigned char device_id, const char * name) { + alexa.onGetState([](unsigned char device_id, const char * name) { return relayStatus(device_id); }); + // Register loop + espurnaRegisterLoop(alexaLoop); + } void alexaLoop() { alexa.handle(); - if (_alexa_change) { - DEBUG_MSG_P(PSTR("[ALEXA] Device #%d state: %s\n"), _alexa_device_id, _alexa_state ? "ON" : "OFF"); - _alexa_change = false; - relayStatus(_alexa_device_id, _alexa_state); + while (!_alexa_dev_changes.empty()) { + AlexaDevChange& change = _alexa_dev_changes.front(); + DEBUG_MSG_P(PSTR("[ALEXA] Device #%u state: %s\n"), change.device_id, change.state ? "ON" : "OFF"); + relayStatus(change.device_id, change.state); + _alexa_dev_changes.pop(); } } diff --git a/code/espurna/api.ino b/code/espurna/api.ino index 8a9a750b..c1c33281 100644 --- a/code/espurna/api.ino +++ b/code/espurna/api.ino @@ -2,7 +2,7 @@ API MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -22,6 +22,10 @@ std::vector _apis; // ----------------------------------------------------------------------------- +bool _apiWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "api", 3) == 0); +} + void _apiWebSocketOnSend(JsonObject& root) { root["apiEnabled"] = getSetting("apiEnabled", API_ENABLED).toInt() == 1; root["apiKey"] = getSetting("apiKey"); @@ -84,11 +88,11 @@ ArRequestHandlerFunction _bindAPI(unsigned int apiID) { } // Get response from callback - char value[API_BUFFER_SIZE]; + 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 (!value) { + if (0 == value[0]) { DEBUG_MSG_P(PSTR("[API] Sending 404 response\n")); request->send(404); return; @@ -98,7 +102,11 @@ ArRequestHandlerFunction _bindAPI(unsigned int apiID) { // Format response according to the Accept header if (_asJson(request)) { char buffer[64]; - snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": %s }"), api.key, value); + 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); @@ -126,6 +134,7 @@ void _onAPIs(AsyncWebServerRequest *request) { root[_apis[i].key] = String(buffer); } root.printTo(output); + jsonBuffer.clear(); request->send(200, "application/json", output); } else { @@ -187,6 +196,7 @@ void apiSetup() { webServer()->on("/apis", HTTP_GET, _onAPIs); webServer()->on("/rpc", HTTP_GET, _onRPC); wsOnSendRegister(_apiWebSocketOnSend); + wsOnReceiveRegister(_apiWebSocketOnReceive); } #endif // WEB_SUPPORT diff --git a/code/espurna/broker.ino b/code/espurna/broker.ino new file mode 100644 index 00000000..6db86e20 --- /dev/null +++ b/code/espurna/broker.ino @@ -0,0 +1,32 @@ +/* + +BROKER MODULE + +Copyright (C) 2017-2018 by Xose Pérez + +*/ + +#if BROKER_SUPPORT + +#include + +std::vector _broker_callbacks; + +// ----------------------------------------------------------------------------- + +void brokerRegister(void (*callback)(const char *, unsigned char, const char *)) { + _broker_callbacks.push_back(callback); +} + +void brokerPublish(const char * topic, unsigned char id, const char * message) { + //DEBUG_MSG_P(PSTR("[BROKER] Message %s[%u] => %s\n"), topic, id, message); + for (unsigned char i=0; i<_broker_callbacks.size(); i++) { + (_broker_callbacks[i])(topic, id, message); + } +} + +void brokerPublish(const char * topic, const char * message) { + brokerPublish(topic, 0, message); +} + +#endif // BROKER_SUPPORT diff --git a/code/espurna/button.ino b/code/espurna/button.ino index 27bef53e..ea550e1f 100644 --- a/code/espurna/button.ino +++ b/code/espurna/button.ino @@ -2,7 +2,7 @@ BUTTON MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -22,14 +22,22 @@ typedef struct { std::vector _buttons; #if MQTT_SUPPORT -#ifdef MQTT_TOPIC_BUTTON + void buttonMQTT(unsigned char id, uint8_t event) { if (id >= _buttons.size()) return; char payload[2]; - snprintf_P(payload, sizeof(payload), PSTR("%d"), event); - mqttSend(MQTT_TOPIC_BUTTON, id, payload); + itoa(event, payload, 10); + mqttSend(MQTT_TOPIC_BUTTON, id, payload, false, false); // 1st bool = force, 2nd = retain } + #endif + +#if WEB_SUPPORT + +bool _buttonWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "btn", 3) == 0); +} + #endif int buttonFromRelay(unsigned int relayID) { @@ -52,16 +60,18 @@ unsigned char buttonAction(unsigned char id, unsigned char event) { if (event == BUTTON_EVENT_DBLCLICK) return (actions >> 8) & 0x0F; if (event == BUTTON_EVENT_LNGCLICK) return (actions >> 12) & 0x0F; if (event == BUTTON_EVENT_LNGLNGCLICK) return (actions >> 16) & 0x0F; + if (event == BUTTON_EVENT_TRIPLECLICK) return (actions >> 20) & 0x0F; return BUTTON_MODE_NONE; } -unsigned long buttonStore(unsigned long pressed, unsigned long click, unsigned long dblclick, unsigned long lngclick, unsigned long lnglngclick) { +unsigned long buttonStore(unsigned long pressed, unsigned long click, unsigned long dblclick, unsigned long lngclick, unsigned long lnglngclick, unsigned long tripleclick) { unsigned int value; value = pressed; value += click << 4; value += dblclick << 8; value += lngclick << 12; value += lnglngclick << 16; + value += tripleclick << 20; return value; } @@ -69,25 +79,25 @@ uint8_t mapEvent(uint8_t event, uint8_t count, uint16_t length) { if (event == EVENT_PRESSED) return BUTTON_EVENT_PRESSED; if (event == EVENT_CHANGED) return BUTTON_EVENT_CLICK; if (event == EVENT_RELEASED) { - if (count == 1) { + if (1 == count) { if (length > BUTTON_LNGLNGCLICK_DELAY) return BUTTON_EVENT_LNGLNGCLICK; if (length > BUTTON_LNGCLICK_DELAY) return BUTTON_EVENT_LNGCLICK; return BUTTON_EVENT_CLICK; } - if (count == 2) return BUTTON_EVENT_DBLCLICK; + if (2 == count) return BUTTON_EVENT_DBLCLICK; + if (3 == count) return BUTTON_EVENT_TRIPLECLICK; } + return BUTTON_EVENT_NONE; } void buttonEvent(unsigned int id, unsigned char event) { - DEBUG_MSG_P(PSTR("[BUTTON] Pressed #%d, event: %d\n"), id, event); + DEBUG_MSG_P(PSTR("[BUTTON] Button #%u event %u\n"), id, event); if (event == 0) return; #if MQTT_SUPPORT - #ifdef MQTT_TOPIC_BUTTON buttonMQTT(id, event); #endif - #endif unsigned char action = buttonAction(id, event); @@ -106,13 +116,19 @@ void buttonEvent(unsigned int id, unsigned char event) { relayStatus(_buttons[id].relayID - 1, false); } } - if (action == BUTTON_MODE_AP) createAP(); + if (action == BUTTON_MODE_AP) wifiStartAP(); + #if defined(JUSTWIFI_ENABLE_WPS) + if (action == BUTTON_MODE_WPS) wifiStartWPS(); + #endif // defined(JUSTWIFI_ENABLE_WPS) + #if defined(JUSTWIFI_ENABLE_SMARTCONFIG) + if (action == BUTTON_MODE_SMART_CONFIG) wifiStartSmartConfig(); + #endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG) if (action == BUTTON_MODE_RESET) { deferredReset(100, CUSTOM_RESET_HARDWARE); } if (action == BUTTON_MODE_FACTORY) { DEBUG_MSG_P(PSTR("\n\nFACTORY RESET\n\n")); - settingsFactoryReset(); + resetSettings(); deferredReset(100, CUSTOM_RESET_FACTORY); } @@ -122,7 +138,7 @@ void buttonSetup() { #ifdef ITEAD_SONOFF_DUAL - unsigned int actions = buttonStore(BUTTON_MODE_NONE, BUTTON_MODE_TOGGLE, BUTTON_MODE_NONE, BUTTON_MODE_NONE, BUTTON_MODE_NONE); + unsigned int actions = buttonStore(BUTTON_MODE_NONE, BUTTON_MODE_TOGGLE, BUTTON_MODE_NONE, BUTTON_MODE_NONE, BUTTON_MODE_NONE, BUTTON_MODE_NONE); _buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, 1}); _buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, 2}); _buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, BUTTON3_RELAY}); @@ -131,58 +147,66 @@ void buttonSetup() { unsigned long btnDelay = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY).toInt(); - #ifdef BUTTON1_PIN + #if BUTTON1_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON1_PRESS, BUTTON1_CLICK, BUTTON1_DBLCLICK, BUTTON1_LNGCLICK, BUTTON1_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON1_PRESS, BUTTON1_CLICK, BUTTON1_DBLCLICK, BUTTON1_LNGCLICK, BUTTON1_LNGLNGCLICK, BUTTON1_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON1_PIN, BUTTON1_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON1_RELAY}); } #endif - #ifdef BUTTON2_PIN + #if BUTTON2_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON2_PRESS, BUTTON2_CLICK, BUTTON2_DBLCLICK, BUTTON2_LNGCLICK, BUTTON2_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON2_PRESS, BUTTON2_CLICK, BUTTON2_DBLCLICK, BUTTON2_LNGCLICK, BUTTON2_LNGLNGCLICK, BUTTON2_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON2_PIN, BUTTON2_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON2_RELAY}); } #endif - #ifdef BUTTON3_PIN + #if BUTTON3_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON3_PRESS, BUTTON3_CLICK, BUTTON3_DBLCLICK, BUTTON3_LNGCLICK, BUTTON3_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON3_PRESS, BUTTON3_CLICK, BUTTON3_DBLCLICK, BUTTON3_LNGCLICK, BUTTON3_LNGLNGCLICK, BUTTON3_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON3_PIN, BUTTON3_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON3_RELAY}); } #endif - #ifdef BUTTON4_PIN + #if BUTTON4_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON4_PRESS, BUTTON4_CLICK, BUTTON4_DBLCLICK, BUTTON4_LNGCLICK, BUTTON4_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON4_PRESS, BUTTON4_CLICK, BUTTON4_DBLCLICK, BUTTON4_LNGCLICK, BUTTON4_LNGLNGCLICK, BUTTON4_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON4_PIN, BUTTON4_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON4_RELAY}); } #endif - #ifdef BUTTON5_PIN + #if BUTTON5_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON5_PRESS, BUTTON5_CLICK, BUTTON5_DBLCLICK, BUTTON5_LNGCLICK, BUTTON5_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON5_PRESS, BUTTON5_CLICK, BUTTON5_DBLCLICK, BUTTON5_LNGCLICK, BUTTON5_LNGLNGCLICK, BUTTON5_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON5_PIN, BUTTON5_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON5_RELAY}); } #endif - #ifdef BUTTON6_PIN + #if BUTTON6_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON6_PRESS, BUTTON6_CLICK, BUTTON6_DBLCLICK, BUTTON6_LNGCLICK, BUTTON6_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON6_PRESS, BUTTON6_CLICK, BUTTON6_DBLCLICK, BUTTON6_LNGCLICK, BUTTON6_LNGLNGCLICK, BUTTON6_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON6_PIN, BUTTON6_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON6_RELAY}); } #endif - #ifdef BUTTON7_PIN + #if BUTTON7_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON7_PRESS, BUTTON7_CLICK, BUTTON7_DBLCLICK, BUTTON7_LNGCLICK, BUTTON7_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON7_PRESS, BUTTON7_CLICK, BUTTON7_DBLCLICK, BUTTON7_LNGCLICK, BUTTON7_LNGLNGCLICK, BUTTON7_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON7_PIN, BUTTON7_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON7_RELAY}); } #endif - #ifdef BUTTON8_PIN + #if BUTTON8_PIN != GPIO_NONE { - unsigned int actions = buttonStore(BUTTON8_PRESS, BUTTON8_CLICK, BUTTON8_DBLCLICK, BUTTON8_LNGCLICK, BUTTON8_LNGLNGCLICK); + unsigned int actions = buttonStore(BUTTON8_PRESS, BUTTON8_CLICK, BUTTON8_DBLCLICK, BUTTON8_LNGCLICK, BUTTON8_LNGLNGCLICK, BUTTON8_TRIPLECLICK); _buttons.push_back({new DebounceEvent(BUTTON8_PIN, BUTTON8_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON8_RELAY}); } #endif #endif - DEBUG_MSG_P(PSTR("[BUTTON] Number of buttons: %d\n"), _buttons.size()); + DEBUG_MSG_P(PSTR("[BUTTON] Number of buttons: %u\n"), _buttons.size()); + + // Websocket Callbacks + #if WEB_SUPPORT + wsOnReceiveRegister(_buttonWebSocketOnReceive); + #endif + + // Register loop + espurnaRegisterLoop(buttonLoop); } @@ -191,11 +215,9 @@ void buttonLoop() { #ifdef ITEAD_SONOFF_DUAL if (Serial.available() >= 4) { - - unsigned char value; if (Serial.read() == 0xA0) { if (Serial.read() == 0x04) { - value = Serial.read(); + unsigned char value = Serial.read(); if (Serial.read() == 0xA1) { // RELAYs and BUTTONs are synchonized in the SIL F330 @@ -228,7 +250,6 @@ void buttonLoop() { } } } - } #else diff --git a/code/espurna/config/all.h b/code/espurna/config/all.h index bec91d47..d21eb007 100644 --- a/code/espurna/config/all.h +++ b/code/espurna/config/all.h @@ -1,26 +1,40 @@ +/* + + If you want to modify the stock configuration but you don't want to touch + the repo files you can define USE_CUSTOM_H in your build settings. + + Arduino IDE: + define it in your boards.txt for the board of your choice. + For instance, for the "Generic ESP8266 Module" with prefix "generic" just add: + + generic.build.extra_flags=-DESP8266 -DUSE_CUSTOM_H + + PlatformIO: + add the setting to your environment or just define global PLATFORMIO_BUILD_FLAGS + + export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'" + + Check https://github.com/xoseperez/espurna/issues/104 + for an example on how to use this file. + +*/ + +#ifdef USE_CUSTOM_H +#include "custom.h" +#endif + #include "version.h" +#include "types.h" #include "arduino.h" #include "hardware.h" #include "defaults.h" #include "general.h" #include "prototypes.h" #include "sensors.h" +#include "dependencies.h" +#include "progmem.h" +#include "debug.h" #ifdef USE_CORE_VERSION_H #include "core_version.h" #endif - -/* - If you want to modify the stock configuration but you don't want to touch - the repo files you can either define USE_CUSTOM_H or remove the - "#ifdef USE_CUSTOM_H" & "#endif" lines and add a "custom.h" - file to this same folder. - Check https://bitbucket.org/xoseperez/espurna/issues/104/general_customh - for an example on how to use this file. - (Define USE_CUSTOM_H on commandline for platformio: - export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'" ) -*/ - -#ifdef USE_CUSTOM_H -#include "custom.h" -#endif diff --git a/code/espurna/config/arduino.h b/code/espurna/config/arduino.h index 2d9d27c1..5a978961 100644 --- a/code/espurna/config/arduino.h +++ b/code/espurna/config/arduino.h @@ -19,6 +19,7 @@ //#define ITEAD_S20 //#define ITEAD_SONOFF_TOUCH //#define ITEAD_SONOFF_POW +//#define ITEAD_SONOFF_POW_R2 //#define ITEAD_SONOFF_DUAL //#define ITEAD_SONOFF_DUAL_R2 //#define ITEAD_SONOFF_4CH @@ -32,6 +33,7 @@ //#define ITEAD_SONOFF_T1_1CH //#define ITEAD_SONOFF_T1_2CH //#define ITEAD_SONOFF_T1_3CH +//#define ITEAD_SONOFF_S31 //#define YJZK_SWITCH_2CH //#define ELECTRODRAGON_WIFI_IOT //#define WORKCHOICE_ECOPLUG @@ -54,40 +56,77 @@ //#define ARILUX_E27 //#define XENON_SM_PW702U //#define AUTHOMETION_LYT8266 +//#define KMC_70011 //#define GENERIC_8CH //#define ARILUX_AL_LC01 //#define ARILUX_AL_LC11 +//#define ARILUX_AL_LC02 +//#define WEMOS_D1_TARPUNA_SHIELD +//#define GIZWITS_WITTY_CLOUD +//#define EUROMATE_WIFI_STECKER_SCHUKO +//#define TONBUX_POWERSTRIP02 +//#define LINGAN_SWA1 +//#define HEYGO_HY02 +//#define MAXCIO_WUS002S +//#define YIDIAN_XSSSA05 +//#define TONBUX_XSSSA06 +//#define GREEN_ESP8266RELAY +//#define IKE_ESPIKE +//#define ARNIEX_SWIFITCH +//#define GENERIC_ESP01S_RELAY_V40 +//#define GENERIC_ESP01S_RGBLED_V10 +//#define GENERIC_ESP01S_DHT11_V10 +//#define GENERIC_ESP01S_DS18B20_V10 +//#define HELTEC_TOUCHRELAY +//#define ZHILDE_EU44_W +//#define LUANI_HVIO +//#define ALLNET_4DUINO_IOT_WLAN_RELAIS +//#define TONBUX_MOSQUITO_KILLER +//#define NEO_COOLCAM_POWER_PLUG_WIFI +//#define ESTINK_WIFI_POWER_STRIP +//#define PILOTAK_ESP_DIN_V1 //-------------------------------------------------------------------------------- // Features (values below are non-default values) //-------------------------------------------------------------------------------- //#define ALEXA_SUPPORT 0 +//#define BROKER_SUPPORT 0 //#define DEBUG_SERIAL_SUPPORT 0 //#define DEBUG_TELNET_SUPPORT 0 //#define DEBUG_UDP_SUPPORT 1 +//#define DEBUG_WEB_SUPPORT 0 //#define DOMOTICZ_SUPPORT 0 //#define HOMEASSISTANT_SUPPORT 0 //#define I2C_SUPPORT 1 -//#define INFLUXDB_SUPPORT 0 +//#define INFLUXDB_SUPPORT 1 //#define IR_SUPPORT 1 //#define LLMNR_SUPPORT 1 // Only with Arduino Core 2.4.0 -//#define MDNS_SUPPORT 0 -//#define NOFUSS_SUPPORT 1 // Only with Arduino Core 2.4.0 +//#define MDNS_SERVER_SUPPORT 0 +//#define MDNS_CLIENT_SUPPORT 1 +//#define MQTT_SUPPORT 0 +//#define NETBIOS_SUPPORT 1 // Only with Arduino Core 2.4.0 +//#define NOFUSS_SUPPORT 1 //#define NTP_SUPPORT 0 //#define RF_SUPPORT 1 +//#define SCHEDULER_SUPPORT 0 //#define SPIFFS_SUPPORT 1 //#define SSDP_SUPPORT 1 //#define TELNET_SUPPORT 0 //#define TERMINAL_SUPPORT 0 +//#define THINGSPEAK_SUPPORT 0 +//#define UART_MQTT_SUPPORT 1 //#define WEB_SUPPORT 0 //-------------------------------------------------------------------------------- // Sensors (values below are non-default values) //-------------------------------------------------------------------------------- +//#define AM2320_SUPPORT 1 //#define ANALOG_SUPPORT 1 +//#define BH1750_SUPPORT 1 //#define BMX280_SUPPORT 1 +//#define CSE7766_SUPPORT 1 //#define DALLAS_SUPPORT 1 //#define DHT_SUPPORT 1 //#define DIGITAL_SUPPORT 1 @@ -96,9 +135,14 @@ //#define EMON_ADS1X15_SUPPORT 1 //#define EMON_ANALOG_SUPPORT 1 //#define EVENTS_SUPPORT 1 +//#define GUVAS12SD_SUPPORT 1 +//#define HCSR04_SUPPORT 1 //#define HLW8012_SUPPORT 1 //#define MHZ19_SUPPORT 1 //#define PMSX003_SUPPORT 1 +//#define PZEM004T_SUPPORT 1 //#define SHT3X_I2C_SUPPORT 1 //#define SI7021_SUPPORT 1 +//#define TMP3X_SUPPORT 1 //#define V9261F_SUPPORT 1 +//#define GEIGER_SUPPORT 1 diff --git a/code/espurna/config/build.h b/code/espurna/config/build.h new file mode 100644 index 00000000..ef312406 --- /dev/null +++ b/code/espurna/config/build.h @@ -0,0 +1,5 @@ +// DO NOT EDIT THIS FILE MANUALLY +// This file is modified by PlatformIO +// This file should not be pushed when modified, untrack changes with: +// git update-index --assume-unchanged code/espurna/config/build.h +#define APP_BUILD_FLAGS "" diff --git a/code/espurna/config/debug.h b/code/espurna/config/debug.h new file mode 100644 index 00000000..3f70386d --- /dev/null +++ b/code/espurna/config/debug.h @@ -0,0 +1,17 @@ +#pragma once + +// ----------------------------------------------------------------------------- +// Debug +// ----------------------------------------------------------------------------- + +#define DEBUG_SUPPORT DEBUG_SERIAL_SUPPORT || DEBUG_UDP_SUPPORT || DEBUG_TELNET_SUPPORT || DEBUG_WEB_SUPPORT + +#if DEBUG_SUPPORT + #define DEBUG_MSG(...) debugSend(__VA_ARGS__) + #define DEBUG_MSG_P(...) debugSend_P(__VA_ARGS__) +#endif + +#ifndef DEBUG_MSG + #define DEBUG_MSG(...) + #define DEBUG_MSG_P(...) +#endif diff --git a/code/espurna/config/defaults.h b/code/espurna/config/defaults.h index 8d192f5d..96bc7047 100644 --- a/code/espurna/config/defaults.h +++ b/code/espurna/config/defaults.h @@ -2,10 +2,37 @@ // Hardware default values // ----------------------------------------------------------------------------- +#define GPIO_NONE 0x99 + // ----------------------------------------------------------------------------- // Buttons // ----------------------------------------------------------------------------- +#ifndef BUTTON1_PIN +#define BUTTON1_PIN GPIO_NONE +#endif +#ifndef BUTTON2_PIN +#define BUTTON2_PIN GPIO_NONE +#endif +#ifndef BUTTON3_PIN +#define BUTTON3_PIN GPIO_NONE +#endif +#ifndef BUTTON4_PIN +#define BUTTON4_PIN GPIO_NONE +#endif +#ifndef BUTTON5_PIN +#define BUTTON5_PIN GPIO_NONE +#endif +#ifndef BUTTON6_PIN +#define BUTTON6_PIN GPIO_NONE +#endif +#ifndef BUTTON7_PIN +#define BUTTON7_PIN GPIO_NONE +#endif +#ifndef BUTTON8_PIN +#define BUTTON8_PIN GPIO_NONE +#endif + #ifndef BUTTON1_PRESS #define BUTTON1_PRESS BUTTON_MODE_NONE #endif @@ -81,6 +108,31 @@ #define BUTTON8_DBLCLICK BUTTON_MODE_NONE #endif +#ifndef BUTTON1_TRIPLECLICK +#define BUTTON1_TRIPLECLICK BUTTON_MODE_SMART_CONFIG +#endif +#ifndef BUTTON2_TRIPLECLICK +#define BUTTON2_TRIPLECLICK BUTTON_MODE_NONE +#endif +#ifndef BUTTON3_TRIPLECLICK +#define BUTTON3_TRIPLECLICK BUTTON_MODE_NONE +#endif +#ifndef BUTTON4_TRIPLECLICK +#define BUTTON4_TRIPLECLICK BUTTON_MODE_NONE +#endif +#ifndef BUTTON5_TRIPLECLICK +#define BUTTON5_TRIPLECLICK BUTTON_MODE_NONE +#endif +#ifndef BUTTON6_TRIPLECLICK +#define BUTTON6_TRIPLECLICK BUTTON_MODE_NONE +#endif +#ifndef BUTTON7_TRIPLECLICK +#define BUTTON7_TRIPLECLICK BUTTON_MODE_NONE +#endif +#ifndef BUTTON8_TRIPLECLICK +#define BUTTON8_TRIPLECLICK BUTTON_MODE_NONE +#endif + #ifndef BUTTON1_LNGCLICK #define BUTTON1_LNGCLICK BUTTON_MODE_RESET #endif @@ -160,6 +212,35 @@ // Relays // ----------------------------------------------------------------------------- +#ifndef DUMMY_RELAY_COUNT +#define DUMMY_RELAY_COUNT 0 +#endif + +#ifndef RELAY1_PIN +#define RELAY1_PIN GPIO_NONE +#endif +#ifndef RELAY2_PIN +#define RELAY2_PIN GPIO_NONE +#endif +#ifndef RELAY3_PIN +#define RELAY3_PIN GPIO_NONE +#endif +#ifndef RELAY4_PIN +#define RELAY4_PIN GPIO_NONE +#endif +#ifndef RELAY5_PIN +#define RELAY5_PIN GPIO_NONE +#endif +#ifndef RELAY6_PIN +#define RELAY6_PIN GPIO_NONE +#endif +#ifndef RELAY7_PIN +#define RELAY7_PIN GPIO_NONE +#endif +#ifndef RELAY8_PIN +#define RELAY8_PIN GPIO_NONE +#endif + #ifndef RELAY1_TYPE #define RELAY1_TYPE RELAY_TYPE_NORMAL #endif @@ -175,7 +256,7 @@ #ifndef RELAY5_TYPE #define RELAY5_TYPE RELAY_TYPE_NORMAL #endif -#ifndef RELAY6_TYPE +#ifndef RELAY6_TYPE #define RELAY6_TYPE RELAY_TYPE_NORMAL #endif #ifndef RELAY7_TYPE @@ -186,28 +267,28 @@ #endif #ifndef RELAY1_RESET_PIN -#define RELAY1_RESET_PIN 0 +#define RELAY1_RESET_PIN GPIO_NONE #endif #ifndef RELAY2_RESET_PIN -#define RELAY2_RESET_PIN 0 +#define RELAY2_RESET_PIN GPIO_NONE #endif #ifndef RELAY3_RESET_PIN -#define RELAY3_RESET_PIN 0 +#define RELAY3_RESET_PIN GPIO_NONE #endif #ifndef RELAY4_RESET_PIN -#define RELAY4_RESET_PIN 0 +#define RELAY4_RESET_PIN GPIO_NONE #endif #ifndef RELAY5_RESET_PIN -#define RELAY5_RESET_PIN 0 +#define RELAY5_RESET_PIN GPIO_NONE #endif #ifndef RELAY6_RESET_PIN -#define RELAY6_RESET_PIN 0 +#define RELAY6_RESET_PIN GPIO_NONE #endif #ifndef RELAY7_RESET_PIN -#define RELAY7_RESET_PIN 0 +#define RELAY7_RESET_PIN GPIO_NONE #endif #ifndef RELAY8_RESET_PIN -#define RELAY8_RESET_PIN 0 +#define RELAY8_RESET_PIN GPIO_NONE #endif #ifndef RELAY1_DELAY_ON @@ -264,6 +345,31 @@ // LEDs // ----------------------------------------------------------------------------- +#ifndef LED1_PIN +#define LED1_PIN GPIO_NONE +#endif +#ifndef LED2_PIN +#define LED2_PIN GPIO_NONE +#endif +#ifndef LED3_PIN +#define LED3_PIN GPIO_NONE +#endif +#ifndef LED4_PIN +#define LED4_PIN GPIO_NONE +#endif +#ifndef LED5_PIN +#define LED5_PIN GPIO_NONE +#endif +#ifndef LED6_PIN +#define LED6_PIN GPIO_NONE +#endif +#ifndef LED7_PIN +#define LED7_PIN GPIO_NONE +#endif +#ifndef LED8_PIN +#define LED8_PIN GPIO_NONE +#endif + #ifndef LED1_MODE #define LED1_MODE LED_MODE_WIFI #endif @@ -318,12 +424,9 @@ // General // ----------------------------------------------------------------------------- -// Needed for ESP8285 boards under Windows using PlatformIO (?) -#ifndef BUTTON_PUSHBUTTON -#define BUTTON_PUSHBUTTON 0 -#define BUTTON_SWITCH 1 -#define BUTTON_DEFAULT_HIGH 2 -#define BUTTON_SET_PULLUP 4 +// Default hostname will be ESPURNA-XXXXXX, where XXXXXX is last 3 octets of chipID +#ifndef HOSTNAME +#define HOSTNAME "" #endif // Relay providers diff --git a/code/espurna/config/dependencies.h b/code/espurna/config/dependencies.h new file mode 100644 index 00000000..21361e61 --- /dev/null +++ b/code/espurna/config/dependencies.h @@ -0,0 +1,50 @@ +#pragma once + +//------------------------------------------------------------------------------ +// Do not change this file unless you know what you are doing +// Configuration settings are in the general.h file +//------------------------------------------------------------------------------ + +#if DEBUG_TELNET_SUPPORT +#undef TELNET_SUPPORT +#define TELNET_SUPPORT 1 +#endif + +#if not WEB_SUPPORT +#undef DEBUG_WEB_SUPPORT +#define DEBUG_WEB_SUPPORT 0 +#endif + +#if not WEB_SUPPORT +#undef SSDP_SUPPORT +#define SSDP_SUPPORT 0 // SSDP support requires web support +#endif + +#if UART_MQTT_SUPPORT +#define MQTT_SUPPORT 1 +#undef TERMINAL_SUPPORT +#define TERMINAL_SUPPORT 0 +#undef DEBUG_SERIAL_SUPPORT +#define DEBUG_SERIAL_SUPPORT 0 +#endif + +#if DOMOTICZ_SUPPORT +#undef MQTT_SUPPORT +#define MQTT_SUPPORT 1 // If Domoticz enabled enable MQTT +#endif + +#if HOMEASSISTANT_SUPPORT +#undef MQTT_SUPPORT +#define MQTT_SUPPORT 1 // If Home Assistant enabled enable MQTT +#endif + +#ifndef ASYNC_TCP_SSL_ENABLED +#if THINGSPEAK_USE_SSL && THINGSPEAK_USE_ASYNC +#undef THINGSPEAK_SUPPORT // Thingspeak in ASYNC mode requires ASYNC_TCP_SSL_ENABLED +#endif +#endif + +#if SCHEDULER_SUPPORT +#undef NTP_SUPPORT +#define NTP_SUPPORT 1 // Scheduler needs NTP +#endif diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index ce5255ae..bb1f551f 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +// // //------------------------------------------------------------------------------ // Do not change this file unless you know what you are doing // Configuration settings are in the settings.h file //------------------------------------------------------------------------------ @@ -7,27 +7,19 @@ // GENERAL //------------------------------------------------------------------------------ -#define ADMIN_PASS "fibonacci" // Default password (WEB, OTA, WIFI) -#define DEVICE_NAME MANUFACTURER "_" DEVICE // Concatenate both to get a unique device name -#define LOOP_DELAY_TIME 10 // Delay for this millis in the main loop [0-250] - -#define ARRAYINIT(type, name, ...) \ - type name[] = {__VA_ARGS__}; - -//------------------------------------------------------------------------------ -// TELNET -//------------------------------------------------------------------------------ +#define DEVICE_NAME MANUFACTURER "_" DEVICE // Concatenate both to get a unique device name -#ifndef TELNET_SUPPORT -#define TELNET_SUPPORT 1 // Enable telnet support by default (3.34Kb) +#ifndef ADMIN_PASS +#define ADMIN_PASS "fibonacci" // Default password (WEB, OTA, WIFI) #endif -#ifndef TELNET_STA -#define TELNET_STA 0 // By default, disallow connections via STA interface +#ifndef USE_PASSWORD +#define USE_PASSWORD 1 // Insecurity caution! Disabling this will disable password querying completely. #endif -#define TELNET_PORT 23 // Port to listen to telnet clients -#define TELNET_MAX_CLIENTS 1 // Max number of concurrent telnet clients +#ifndef LOOP_DELAY_TIME +#define LOOP_DELAY_TIME 10 // Delay for this millis in the main loop [0-250] +#endif //------------------------------------------------------------------------------ // DEBUG @@ -47,6 +39,26 @@ #define SERIAL_BAUDRATE 115200 // Default baudrate #endif +#ifndef DEBUG_ADD_TIMESTAMP +#define DEBUG_ADD_TIMESTAMP 1 // Add timestamp to debug messages + // (in millis overflowing every 1000 seconds) +#endif + +// Second serial port (used for RX) + +#ifndef SERIAL_RX_ENABLED +#define SERIAL_RX_ENABLED 0 // Secondary serial port for RX +#endif + +#ifndef SERIAL_RX_PORT +#define SERIAL_RX_PORT Serial // This setting is usually defined + // in the hardware.h file for those + // boards that require it +#endif + +#ifndef SERIAL_RX_BAUDRATE +#define SERIAL_RX_BAUDRATE 115200 // Default baudrate +#endif //------------------------------------------------------------------------------ @@ -57,39 +69,57 @@ #ifndef DEBUG_UDP_SUPPORT #define DEBUG_UDP_SUPPORT 0 // Enable UDP debug log #endif + +#ifndef DEBUG_UDP_IP #define DEBUG_UDP_IP IPAddress(192, 168, 1, 100) -#define DEBUG_UDP_PORT 8113 +#endif + +#ifndef DEBUG_UDP_PORT +#define DEBUG_UDP_PORT 514 +#endif + +// If DEBUG_UDP_PORT is set to 514 syslog format is assumed +// (https://tools.ietf.org/html/rfc3164) +// DEBUG_UDP_FAC_PRI is the facility+priority +#define DEBUG_UDP_FAC_PRI (SYSLOG_LOCAL0 | SYSLOG_DEBUG) //------------------------------------------------------------------------------ #ifndef DEBUG_TELNET_SUPPORT -#define DEBUG_TELNET_SUPPORT TELNET_SUPPORT // Enable telnet debug log if telnet is enabled too +#define DEBUG_TELNET_SUPPORT 1 // Enable telnet debug log (will only work if TELNET_SUPPORT is also 1) #endif //------------------------------------------------------------------------------ -// General debug options and macros -#define DEBUG_FORMAT_MAX_LENGTH 80 -#define DEBUG_SUPPORT DEBUG_SERIAL_SUPPORT || DEBUG_UDP_SUPPORT || DEBUG_TELNET_SUPPORT +#ifndef DEBUG_WEB_SUPPORT +#define DEBUG_WEB_SUPPORT 1 // Enable web debug log (will only work if WEB_SUPPORT is also 1) +#endif + +//------------------------------------------------------------------------------ +// TELNET +//------------------------------------------------------------------------------ -#if DEBUG_SUPPORT - #define DEBUG_MSG(...) debugSend(__VA_ARGS__) - #define DEBUG_MSG_P(...) debugSend_P(__VA_ARGS__) +#ifndef TELNET_SUPPORT +#define TELNET_SUPPORT 1 // Enable telnet support by default (3.34Kb) #endif -#ifndef DEBUG_MSG - #define DEBUG_MSG(...) - #define DEBUG_MSG_P(...) +#ifndef TELNET_STA +#define TELNET_STA 0 // By default, disallow connections via STA interface #endif +#define TELNET_PORT 23 // Port to listen to telnet clients +#define TELNET_MAX_CLIENTS 1 // Max number of concurrent telnet clients + //------------------------------------------------------------------------------ // TERMINAL //------------------------------------------------------------------------------ #ifndef TERMINAL_SUPPORT -#define TERMINAL_SUPPORT 1 // Enable terminal commands (0.97Kb) +#define TERMINAL_SUPPORT 1 // Enable terminal commands (0.97Kb) #endif +#define TERMINAL_BUFFER_SIZE 128 // Max size for commands commands + //------------------------------------------------------------------------------ // SYSTEM CHECK //------------------------------------------------------------------------------ @@ -98,26 +128,44 @@ #define SYSTEM_CHECK_ENABLED 1 // Enable crash check by default #endif +#ifndef SYSTEM_CHECK_TIME #define SYSTEM_CHECK_TIME 60000 // The system is considered stable after these many millis +#endif + +#ifndef SYSTEM_CHECK_MAX #define SYSTEM_CHECK_MAX 5 // After this many crashes on boot // the system is flagged as unstable +#endif //------------------------------------------------------------------------------ // EEPROM //------------------------------------------------------------------------------ #define EEPROM_SIZE 4096 // EEPROM size in bytes +//#define EEPROM_RORATE_SECTORS 2 // Number of sectors to use for EEPROM rotation + // If not defined the firmware will use a number based + // on the number of available sectors + #define EEPROM_RELAY_STATUS 0 // Address for the relay status (1 byte) #define EEPROM_ENERGY_COUNT 1 // Address for the energy counter (4 bytes) #define EEPROM_CUSTOM_RESET 5 // Address for the reset reason (1 byte) #define EEPROM_CRASH_COUNTER 6 // Address for the crash counter (1 byte) -#define EEPROM_DATA_END 7 // End of custom EEPROM data block +#define EEPROM_MESSAGE_ID 7 // Address for the MQTT message id (4 bytes) +#define EEPROM_ROTATE_DATA 11 // Reserved for the EEPROM_ROTATE library (3 bytes) +#define EEPROM_DATA_END 14 // End of custom EEPROM data block //------------------------------------------------------------------------------ // HEARTBEAT //------------------------------------------------------------------------------ +#ifndef HEARTBEAT_ENABLED +#define HEARTBEAT_ENABLED 1 +#endif + +#ifndef HEARTBEAT_INTERVAL #define HEARTBEAT_INTERVAL 300000 // Interval between heartbeat messages (in ms) +#endif + #define UPTIME_OVERFLOW 4294967295 // Uptime overflow value // Topics that will be reported in heartbeat @@ -134,361 +182,545 @@ #define HEARTBEAT_REPORT_HOSTNAME 1 #define HEARTBEAT_REPORT_APP 1 #define HEARTBEAT_REPORT_VERSION 1 +#define HEARTBEAT_REPORT_BOARD 1 #define HEARTBEAT_REPORT_INTERVAL 0 //------------------------------------------------------------------------------ -// RESET +// Load average //------------------------------------------------------------------------------ -#define CUSTOM_RESET_HARDWARE 1 // Reset from hardware button -#define CUSTOM_RESET_WEB 2 // Reset from web interface -#define CUSTOM_RESET_TERMINAL 3 // Reset from terminal -#define CUSTOM_RESET_MQTT 4 // Reset via MQTT -#define CUSTOM_RESET_RPC 5 // Reset via RPC (HTTP) -#define CUSTOM_RESET_OTA 6 // Reset after successful OTA update -#define CUSTOM_RESET_HTTP 7 // Reset via HTTP GET -#define CUSTOM_RESET_NOFUSS 8 // Reset after successful NOFUSS update -#define CUSTOM_RESET_UPGRADE 9 // Reset after update from web interface -#define CUSTOM_RESET_FACTORY 10 // Factory reset from terminal - -#define CUSTOM_RESET_MAX 10 - -PROGMEM const char custom_reset_hardware[] = "Hardware button"; -PROGMEM const char custom_reset_web[] = "Reboot from web interface"; -PROGMEM const char custom_reset_terminal[] = "Reboot from terminal"; -PROGMEM const char custom_reset_mqtt[] = "Reboot from MQTT"; -PROGMEM const char custom_reset_rpc[] = "Reboot from RPC"; -PROGMEM const char custom_reset_ota[] = "Reboot after successful OTA update"; -PROGMEM const char custom_reset_http[] = "Reboot from HTTP"; -PROGMEM const char custom_reset_nofuss[] = "Reboot after successful NoFUSS update"; -PROGMEM const char custom_reset_upgrade[] = "Reboot after successful web update"; -PROGMEM const char custom_reset_factory[] = "Factory reset"; -PROGMEM const char* const custom_reset_string[] = { - custom_reset_hardware, custom_reset_web, custom_reset_terminal, - custom_reset_mqtt, custom_reset_rpc, custom_reset_ota, - custom_reset_http, custom_reset_nofuss, custom_reset_upgrade, - custom_reset_factory -}; +#ifndef LOADAVG_INTERVAL +#define LOADAVG_INTERVAL 30000 // Interval between calculating load average (in ms) +#endif + +#ifndef LOADAVG_REPORT +#define LOADAVG_REPORT 1 // Should we report Load average over MQTT? +#endif //------------------------------------------------------------------------------ // BUTTON //------------------------------------------------------------------------------ +#ifndef BUTTON_DEBOUNCE_DELAY #define BUTTON_DEBOUNCE_DELAY 50 // Debounce delay (ms) +#endif + +#ifndef BUTTON_DBLCLICK_DELAY #define BUTTON_DBLCLICK_DELAY 500 // Time in ms to wait for a second (or third...) click +#endif + +#ifndef BUTTON_LNGCLICK_DELAY #define BUTTON_LNGCLICK_DELAY 1000 // Time in ms holding the button down to get a long click -#define BUTTON_LNGLNGCLICK_DELAY 10000 // Time in ms holding the button down to get a long-long click +#endif -#define BUTTON_EVENT_NONE 0 -#define BUTTON_EVENT_PRESSED 1 -#define BUTTON_EVENT_RELEASED 2 -#define BUTTON_EVENT_CLICK 2 -#define BUTTON_EVENT_DBLCLICK 3 -#define BUTTON_EVENT_LNGCLICK 4 -#define BUTTON_EVENT_LNGLNGCLICK 5 - -#define BUTTON_MODE_NONE 0 -#define BUTTON_MODE_TOGGLE 1 -#define BUTTON_MODE_ON 2 -#define BUTTON_MODE_OFF 3 -#define BUTTON_MODE_AP 4 -#define BUTTON_MODE_RESET 5 -#define BUTTON_MODE_PULSE 6 -#define BUTTON_MODE_FACTORY 7 +#ifndef BUTTON_LNGLNGCLICK_DELAY +#define BUTTON_LNGLNGCLICK_DELAY 10000 // Time in ms holding the button down to get a long-long click +#endif //------------------------------------------------------------------------------ // RELAY //------------------------------------------------------------------------------ -#define RELAY_BOOT_OFF 0 -#define RELAY_BOOT_ON 1 -#define RELAY_BOOT_SAME 2 -#define RELAY_BOOT_TOOGLE 3 - -#define RELAY_TYPE_NORMAL 0 -#define RELAY_TYPE_INVERSE 1 -#define RELAY_TYPE_LATCHED 2 - -#define RELAY_SYNC_ANY 0 -#define RELAY_SYNC_NONE_OR_ONE 1 -#define RELAY_SYNC_ONE 2 -#define RELAY_SYNC_SAME 3 - -#define RELAY_PULSE_NONE 0 -#define RELAY_PULSE_OFF 1 -#define RELAY_PULSE_ON 2 - -#define RELAY_PROVIDER_RELAY 0 -#define RELAY_PROVIDER_DUAL 1 -#define RELAY_PROVIDER_LIGHT 2 -#define RELAY_PROVIDER_RFBRIDGE 3 - // Default boot mode: 0 means OFF, 1 ON and 2 whatever was before -#define RELAY_BOOT_MODE RELAY_BOOT_OFF +#ifndef RELAY_BOOT_MODE +#define RELAY_BOOT_MODE RELAY_BOOT_OFF +#endif // 0 means ANY, 1 zero or one and 2 one and only one -#define RELAY_SYNC RELAY_SYNC_ANY +#ifndef RELAY_SYNC +#define RELAY_SYNC RELAY_SYNC_ANY +#endif // Default pulse mode: 0 means no pulses, 1 means normally off, 2 normally on -#define RELAY_PULSE_MODE RELAY_PULSE_NONE +#ifndef RELAY_PULSE_MODE +#define RELAY_PULSE_MODE RELAY_PULSE_NONE +#endif // Default pulse time in seconds -#define RELAY_PULSE_TIME 1.0 +#ifndef RELAY_PULSE_TIME +#define RELAY_PULSE_TIME 1.0 +#endif // Relay requests flood protection window - in seconds -#define RELAY_FLOOD_WINDOW 3 +#ifndef RELAY_FLOOD_WINDOW +#define RELAY_FLOOD_WINDOW 3 +#endif // Allowed actual relay changes inside requests flood protection window -#define RELAY_FLOOD_CHANGES 5 +#ifndef RELAY_FLOOD_CHANGES +#define RELAY_FLOOD_CHANGES 5 +#endif // Pulse with in milliseconds for a latched relay -#define RELAY_LATCHING_PULSE 10 +#ifndef RELAY_LATCHING_PULSE +#define RELAY_LATCHING_PULSE 10 +#endif // Do not save relay state after these many milliseconds -#define RELAY_SAVE_DELAY 1000 +#ifndef RELAY_SAVE_DELAY +#define RELAY_SAVE_DELAY 1000 +#endif -//------------------------------------------------------------------------------ -// I18N -//------------------------------------------------------------------------------ +// ----------------------------------------------------------------------------- +// WIFI +// ----------------------------------------------------------------------------- -#define TMP_CELSIUS 0 -#define TMP_FAHRENHEIT 1 +#ifndef WIFI_CONNECT_TIMEOUT +#define WIFI_CONNECT_TIMEOUT 60000 // Connecting timeout for WIFI in ms +#endif -//------------------------------------------------------------------------------ -// LED -//------------------------------------------------------------------------------ +#ifndef WIFI_RECONNECT_INTERVAL +#define WIFI_RECONNECT_INTERVAL 180000 // If could not connect to WIFI, retry after this time in ms +#endif -#define LED_MODE_MQTT 0 // LED will be managed from MQTT (OFF by default) -#define LED_MODE_WIFI 1 // LED will blink according to the WIFI status -#define LED_MODE_FOLLOW 2 // LED will follow state of linked relay (check RELAY#_LED) -#define LED_MODE_FOLLOW_INVERSE 3 // LED will follow the opposite state of linked relay (check RELAY#_LED) -#define LED_MODE_FINDME 4 // LED will be ON if all relays are OFF -#define LED_MODE_MIXED 5 // A mixed between WIFI and FINDME -#define LED_MODE_ON 6 // LED always ON -#define LED_MODE_OFF 7 // LED always OFF +#ifndef WIFI_MAX_NETWORKS +#define WIFI_MAX_NETWORKS 5 // Max number of WIFI connection configurations +#endif -// ----------------------------------------------------------------------------- -// WIFI -// ----------------------------------------------------------------------------- +#ifndef WIFI_AP_CAPTIVE +#define WIFI_AP_CAPTIVE 1 // Captive portal enabled when in AP mode +#endif + + +#ifndef WIFI_SLEEP_MODE +#define WIFI_SLEEP_MODE WIFI_NONE_SLEEP // WIFI_NONE_SLEEP, WIFI_LIGHT_SLEEP or WIFI_MODEM_SLEEP +#endif + +#ifndef WIFI_SCAN_NETWORKS +#define WIFI_SCAN_NETWORKS 1 // Perform a network scan before connecting +#endif + +// Optional hardcoded configuration (up to 2 networks) +#ifndef WIFI1_SSID +#define WIFI1_SSID "" +#endif + +#ifndef WIFI1_PASS +#define WIFI1_PASS "" +#endif + +#ifndef WIFI1_IP +#define WIFI1_IP "" +#endif + +#ifndef WIFI1_GW +#define WIFI1_GW "" +#endif + +#ifndef WIFI1_MASK +#define WIFI1_MASK "" +#endif + +#ifndef WIFI1_DNS +#define WIFI1_DNS "" +#endif + +#ifndef WIFI2_SSID +#define WIFI2_SSID "" +#endif + +#ifndef WIFI2_PASS +#define WIFI2_PASS "" +#endif + +#ifndef WIFI2_IP +#define WIFI2_IP "" +#endif + +#ifndef WIFI2_GW +#define WIFI2_GW "" +#endif + +#ifndef WIFI2_MASK +#define WIFI2_MASK "" +#endif -#define WIFI_CONNECT_TIMEOUT 60000 // Connecting timeout for WIFI in ms -#define WIFI_RECONNECT_INTERVAL 180000 // If could not connect to WIFI, retry after this time in ms -#define WIFI_MAX_NETWORKS 5 // Max number of WIFI connection configurations -#define WIFI_AP_MODE AP_MODE_ALONE -#define WIFI_SLEEP_ENABLED 1 // Enable WiFi light sleep +#ifndef WIFI2_DNS +#define WIFI2_DNS "" +#endif -// Optional hardcoded configuration (up to 2 different networks) -//#define WIFI1_SSID "..." -//#define WIFI1_PASS "..." -//#define WIFI1_IP "192.168.1.201" -//#define WIFI1_GW "192.168.1.1" -//#define WIFI1_MASK "255.255.255.0" -//#define WIFI1_DNS "8.8.8.8" -//#define WIFI2_SSID "..." -//#define WIFI2_PASS "..." +#ifndef WIFI_RSSI_1M +#define WIFI_RSSI_1M -30 // Calibrate it with your router reading the RSSI at 1m +#endif + +#ifndef WIFI_PROPAGATION_CONST +#define WIFI_PROPAGATION_CONST 4 // This is typically something between 2.7 to 4.3 (free space is 2) +#endif // ----------------------------------------------------------------------------- // WEB // ----------------------------------------------------------------------------- #ifndef WEB_SUPPORT -#define WEB_SUPPORT 1 // Enable web support (http, api, 121.65Kb) +#define WEB_SUPPORT 1 // Enable web support (http, api, 121.65Kb) #endif #ifndef WEB_EMBEDDED -#define WEB_EMBEDDED 1 // Build the firmware with the web interface embedded in +#define WEB_EMBEDDED 1 // Build the firmware with the web interface embedded in #endif // This is not working at the moment!! -// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core staging version. -#define WEB_SSL_ENABLED 0 // Use HTTPS web interface +// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0 +#ifndef WEB_SSL_ENABLED +#define WEB_SSL_ENABLED 0 // Use HTTPS web interface +#endif -#define WEB_MODE_NORMAL 0 -#define WEB_MODE_PASSWORD 1 +#ifndef WEB_USERNAME +#define WEB_USERNAME "admin" // HTTP username +#endif -#define WEB_USERNAME "admin" // HTTP username -#define WEB_FORCE_PASS_CHANGE 1 // Force the user to change the password if default one -#define WEB_PORT 80 // HTTP port +#ifndef WEB_FORCE_PASS_CHANGE +#define WEB_FORCE_PASS_CHANGE 1 // Force the user to change the password if default one +#endif + +#ifndef WEB_PORT +#define WEB_PORT 80 // HTTP port +#endif // ----------------------------------------------------------------------------- // WEBSOCKETS // ----------------------------------------------------------------------------- // This will only be enabled if WEB_SUPPORT is 1 (this is the default value) +#ifndef WS_AUTHENTICATION +#define WS_AUTHENTICATION 1 // WS authentication ON by default (see #507) +#endif + +#ifndef WS_BUFFER_SIZE +#define WS_BUFFER_SIZE 5 // Max number of secured websocket connections +#endif + +#ifndef WS_TIMEOUT +#define WS_TIMEOUT 1800000 // Timeout for secured websocket +#endif -#define WS_BUFFER_SIZE 5 // Max number of secured websocket connections -#define WS_TIMEOUT 1800000 // Timeout for secured websocket +#ifndef WS_UPDATE_INTERVAL +#define WS_UPDATE_INTERVAL 30000 // Update clients every 30 seconds +#endif // ----------------------------------------------------------------------------- // API // ----------------------------------------------------------------------------- // This will only be enabled if WEB_SUPPORT is 1 (this is the default value) +#ifndef API_ENABLED +#define API_ENABLED 0 // Do not enable API by default +#endif -#define API_ENABLED 0 // Do not enable API by default -#define API_BUFFER_SIZE 15 // Size of the buffer for HTTP GET API responses -#define API_REAL_TIME_VALUES 0 // Show filtered/median values by default (0 => median, 1 => real time) +#ifndef API_BUFFER_SIZE +#define API_BUFFER_SIZE 15 // Size of the buffer for HTTP GET API responses +#endif -// ----------------------------------------------------------------------------- -// UI -// ----------------------------------------------------------------------------- +#ifndef API_REAL_TIME_VALUES +#define API_REAL_TIME_VALUES 0 // Show filtered/median values by default (0 => median, 1 => real time) +#endif -#define UI_TAG_INPUT 0 -#define UI_TAG_CHECKBOX 1 -#define UI_TAG_SELECT 2 // ----------------------------------------------------------------------------- // MDNS / LLMNR / NETBIOS / SSDP // ----------------------------------------------------------------------------- -#ifndef MDNS_SUPPORT -#define MDNS_SUPPORT 1 // Publish services using mDNS by default (1.84Kb) +#ifndef MDNS_SERVER_SUPPORT +#define MDNS_SERVER_SUPPORT 1 // Publish services using mDNS by default (1.48Kb) +#endif + +#ifndef MDNS_CLIENT_SUPPORT +#define MDNS_CLIENT_SUPPORT 0 // Resolve mDNS names (3.44Kb) #endif #ifndef LLMNR_SUPPORT -#define LLMNR_SUPPORT 0 // Publish device using LLMNR protocol by default (1.95Kb) - requires 2.4.0 +#define LLMNR_SUPPORT 0 // Publish device using LLMNR protocol by default (1.95Kb) - requires 2.4.0 #endif #ifndef NETBIOS_SUPPORT -#define NETBIOS_SUPPORT 0 // Publish device using NetBIOS protocol by default (1.26Kb) - requires 2.4.0 +#define NETBIOS_SUPPORT 0 // Publish device using NetBIOS protocol by default (1.26Kb) - requires 2.4.0 #endif #ifndef SSDP_SUPPORT -#define SSDP_SUPPORT 0 // Publish device using SSDP protocol by default (3.32Kb) +#define SSDP_SUPPORT 0 // Publish device using SSDP protocol by default (4.59Kb) + // Not compatible with ALEXA_SUPPORT at the moment +#endif + +#ifndef SSDP_DEVICE_TYPE +#define SSDP_DEVICE_TYPE "upnp:rootdevice" +//#define SSDP_DEVICE_TYPE "urn:schemas-upnp-org:device:BinaryLight:1" #endif + // ----------------------------------------------------------------------------- // SPIFFS // ----------------------------------------------------------------------------- #ifndef SPIFFS_SUPPORT -#define SPIFFS_SUPPORT 0 // Do not add support for SPIFFS by default +#define SPIFFS_SUPPORT 0 // Do not add support for SPIFFS by default #endif // ----------------------------------------------------------------------------- // OTA // ----------------------------------------------------------------------------- -#define OTA_PORT 8266 // OTA port +#ifndef OTA_PORT +#define OTA_PORT 8266 // OTA port +#endif + +#define OTA_GITHUB_FP "D7:9F:07:61:10:B3:92:93:E3:49:AC:89:84:5B:03:80:C1:9E:2F:8B" // ----------------------------------------------------------------------------- // NOFUSS // ----------------------------------------------------------------------------- #ifndef NOFUSS_SUPPORT -#define NOFUSS_SUPPORT 0 // Do not enable support for NoFuss by default (12.65Kb) +#define NOFUSS_SUPPORT 0 // Do not enable support for NoFuss by default (12.65Kb) +#endif + +#ifndef NOFUSS_ENABLED +#define NOFUSS_ENABLED 0 // Do not perform NoFUSS updates by default #endif -#define NOFUSS_ENABLED 0 // Do not perform NoFUSS updates by default -#define NOFUSS_SERVER "" // Default NoFuss Server -#define NOFUSS_INTERVAL 3600000 // Check for updates every hour +#ifndef NOFUSS_SERVER +#define NOFUSS_SERVER "" // Default NoFuss Server +#endif + +#ifndef NOFUSS_INTERVAL +#define NOFUSS_INTERVAL 3600000 // Check for updates every hour +#endif + +// ----------------------------------------------------------------------------- +// UART <-> MQTT +// ----------------------------------------------------------------------------- + +#ifndef UART_MQTT_SUPPORT +#define UART_MQTT_SUPPORT 0 // No support by default +#endif + +#ifndef UART_MQTT_USE_SOFT +#define UART_MQTT_USE_SOFT 0 // Use SoftwareSerial +#endif + +#ifndef UART_MQTT_HW_PORT +#define UART_MQTT_HW_PORT Serial // Hardware serial port (if UART_MQTT_USE_SOFT == 0) +#endif + +#ifndef UART_MQTT_RX_PIN +#define UART_MQTT_RX_PIN 4 // RX PIN (if UART_MQTT_USE_SOFT == 1) +#endif + +#ifndef UART_MQTT_TX_PIN +#define UART_MQTT_TX_PIN 5 // TX PIN (if UART_MQTT_USE_SOFT == 1) +#endif + +#ifndef UART_MQTT_BAUDRATE +#define UART_MQTT_BAUDRATE 115200 // Serial speed +#endif + +#ifndef UART_MQTT_TERMINATION +#define UART_MQTT_TERMINATION '\n' // Termination character +#endif + +#define UART_MQTT_BUFFER_SIZE 100 // UART buffer size // ----------------------------------------------------------------------------- // MQTT // ----------------------------------------------------------------------------- #ifndef MQTT_SUPPORT -#define MQTT_SUPPORT 1 // MQTT support (22.38Kb async, 12.48Kb sync) +#define MQTT_SUPPORT 1 // MQTT support (22.38Kb async, 12.48Kb sync) #endif #ifndef MQTT_USE_ASYNC -#define MQTT_USE_ASYNC 1 // Use AysncMQTTClient (1) or PubSubClient +#define MQTT_USE_ASYNC 1 // Use AysncMQTTClient (1) or PubSubClient (0) #endif // MQTT OVER SSL // Using MQTT over SSL works pretty well but generates problems with the web interface. // It could be a good idea to use it in conjuntion with WEB_SUPPORT=0. -// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core staging version. +// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0. // -// You can use it with MQTT_USE_ASYNC=1 (AsyncMqttClient library) +// You can use SSL with MQTT_USE_ASYNC=1 (AsyncMqttClient library) // but you might experience hiccups on the web interface, so my recommendation is: // WEB_SUPPORT=0 // -// If you use it with MQTT_USE_ASYNC=0 (PubSubClient library) +// If you use SSL with MQTT_USE_ASYNC=0 (PubSubClient library) // you will have to disable all the modules that use ESPAsyncTCP, that is: -// ALEXA_SUPPORT=0, INFLUXDB_SUPPORT=0, TELNET_SUPPORT=0 and WEB_SUPPORT=0 +// ALEXA_SUPPORT=0, INFLUXDB_SUPPORT=0, TELNET_SUPPORT=0, THINGSPEAK_SUPPORT=0 and WEB_SUPPORT=0 // // You will need the fingerprint for your MQTT server, example for CloudMQTT: // $ echo -n | openssl s_client -connect m11.cloudmqtt.com:24055 > cloudmqtt.pem // $ openssl x509 -noout -in cloudmqtt.pem -fingerprint -sha1 -#define MQTT_SSL_ENABLED 0 // By default MQTT over SSL will not be enabled -#define MQTT_SSL_FINGERPRINT "" // SSL fingerprint of the server +#ifndef MQTT_SSL_ENABLED +#define MQTT_SSL_ENABLED 0 // By default MQTT over SSL will not be enabled +#endif + +#ifndef MQTT_SSL_FINGERPRINT +#define MQTT_SSL_FINGERPRINT "" // SSL fingerprint of the server +#endif + + +#ifndef MQTT_ENABLED +#define MQTT_ENABLED 0 // Do not enable MQTT connection by default +#endif + +#ifndef MQTT_AUTOCONNECT +#define MQTT_AUTOCONNECT 1 // If enabled and MDNS_SERVER_SUPPORT=1 will perform an autodiscover and + // autoconnect to the first MQTT broker found if none defined +#endif + +#ifndef MQTT_SERVER +#define MQTT_SERVER "" // Default MQTT broker address +#endif + +#ifndef MQTT_USER +#define MQTT_USER "" // Default MQTT broker usename +#endif + +#ifndef MQTT_PASS +#define MQTT_PASS "" // Default MQTT broker password +#endif + +#ifndef MQTT_PORT +#define MQTT_PORT 1883 // MQTT broker port +#endif + +#ifndef MQTT_TOPIC +#define MQTT_TOPIC "{hostname}" // Default MQTT base topic +#endif + +#ifndef MQTT_RETAIN +#define MQTT_RETAIN true // MQTT retain flag +#endif + +#ifndef MQTT_QOS +#define MQTT_QOS 0 // MQTT QoS value for all messages +#endif + +#ifndef MQTT_KEEPALIVE +#define MQTT_KEEPALIVE 300 // MQTT keepalive value +#endif + + +#ifndef MQTT_RECONNECT_DELAY_MIN +#define MQTT_RECONNECT_DELAY_MIN 5000 // Try to reconnect in 5 seconds upon disconnection +#endif + +#ifndef MQTT_RECONNECT_DELAY_STEP +#define MQTT_RECONNECT_DELAY_STEP 5000 // Increase the reconnect delay in 5 seconds after each failed attempt +#endif + +#ifndef MQTT_RECONNECT_DELAY_MAX +#define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most +#endif + + +#ifndef MQTT_SKIP_RETAINED +#define MQTT_SKIP_RETAINED 1 // Skip retained messages on connection +#endif + +#ifndef MQTT_SKIP_TIME +#define MQTT_SKIP_TIME 1000 // Skip messages for 1 second anter connection +#endif + + +#ifndef MQTT_USE_JSON +#define MQTT_USE_JSON 0 // Group messages in a JSON body +#endif + +#ifndef MQTT_USE_JSON_DELAY +#define MQTT_USE_JSON_DELAY 100 // Wait this many ms before grouping messages +#endif + +#ifndef MQTT_QUEUE_MAX_SIZE +#define MQTT_QUEUE_MAX_SIZE 20 // Size of the MQTT queue when MQTT_USE_JSON is enabled +#endif + -#define MQTT_ENABLED 0 // Do not enable MQTT connection by default -#define MQTT_AUTOCONNECT 1 // If enabled and MDNS_SUPPORT=1 will perform an autodiscover and - // autoconnect to the first MQTT broker found if none defined -#define MQTT_SERVER "" // Default MQTT broker address -#define MQTT_USER "" // Default MQTT broker usename -#define MQTT_PASS "" // Default MQTT broker password -#define MQTT_PORT 1883 // MQTT broker port -#define MQTT_TOPIC "{identifier}" // Default MQTT base topic -#define MQTT_RETAIN true // MQTT retain flag -#define MQTT_QOS 0 // MQTT QoS value for all messages -#define MQTT_KEEPALIVE 30 // MQTT keepalive value +// These are the properties that will be sent when useJson is true +#ifndef MQTT_ENQUEUE_IP +#define MQTT_ENQUEUE_IP 1 +#endif -#define MQTT_RECONNECT_DELAY_MIN 5000 // Try to reconnect in 5 seconds upon disconnection -#define MQTT_RECONNECT_DELAY_STEP 5000 // Increase the reconnect delay in 5 seconds after each failed attempt -#define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most +#ifndef MQTT_ENQUEUE_MAC +#define MQTT_ENQUEUE_MAC 1 +#endif -#define MQTT_SKIP_RETAINED 1 // Skip retained messages on connection -#define MQTT_SKIP_TIME 1000 // Skip messages for 1 second anter connection +#ifndef MQTT_ENQUEUE_HOSTNAME +#define MQTT_ENQUEUE_HOSTNAME 1 +#endif -#define MQTT_USE_JSON 0 // Group messages in a JSON body -#define MQTT_USE_JSON_DELAY 100 // Wait this many ms before grouping messages -#define MQTT_QUEUE_MAX_SIZE 10 // Size of the MQTT queue when MQTT_USE_JSON is enabled +#ifndef MQTT_ENQUEUE_DATETIME +#define MQTT_ENQUEUE_DATETIME 1 +#endif +#ifndef MQTT_ENQUEUE_MESSAGE_ID +#define MQTT_ENQUEUE_MESSAGE_ID 1 +#endif // These particles will be concatenated to the MQTT_TOPIC base to form the actual topic -#define MQTT_TOPIC_JSON "data" -#define MQTT_TOPIC_ACTION "action" -#define MQTT_TOPIC_RELAY "relay" -#define MQTT_TOPIC_LED "led" -#define MQTT_TOPIC_BUTTON "button" -#define MQTT_TOPIC_IP "ip" -#define MQTT_TOPIC_VERSION "version" -#define MQTT_TOPIC_UPTIME "uptime" -#define MQTT_TOPIC_DATETIME "datetime" -#define MQTT_TOPIC_FREEHEAP "freeheap" -#define MQTT_TOPIC_VCC "vcc" -#define MQTT_TOPIC_STATUS "status" -#define MQTT_TOPIC_MAC "mac" -#define MQTT_TOPIC_RSSI "rssi" -#define MQTT_TOPIC_APP "app" -#define MQTT_TOPIC_INTERVAL "interval" -#define MQTT_TOPIC_HOSTNAME "host" -#define MQTT_TOPIC_TIME "time" -#define MQTT_TOPIC_RFOUT "rfout" -#define MQTT_TOPIC_RFIN "rfin" -#define MQTT_TOPIC_RFLEARN "rflearn" +#define MQTT_TOPIC_JSON "data" +#define MQTT_TOPIC_ACTION "action" +#define MQTT_TOPIC_RELAY "relay" +#define MQTT_TOPIC_LED "led" +#define MQTT_TOPIC_BUTTON "button" +#define MQTT_TOPIC_IP "ip" +#define MQTT_TOPIC_VERSION "version" +#define MQTT_TOPIC_UPTIME "uptime" +#define MQTT_TOPIC_DATETIME "datetime" +#define MQTT_TOPIC_FREEHEAP "freeheap" +#define MQTT_TOPIC_VCC "vcc" +#define MQTT_TOPIC_STATUS "status" +#define MQTT_TOPIC_MAC "mac" +#define MQTT_TOPIC_RSSI "rssi" +#define MQTT_TOPIC_MESSAGE_ID "id" +#define MQTT_TOPIC_APP "app" +#define MQTT_TOPIC_INTERVAL "interval" +#define MQTT_TOPIC_HOSTNAME "host" +#define MQTT_TOPIC_TIME "time" +#define MQTT_TOPIC_RFOUT "rfout" +#define MQTT_TOPIC_RFIN "rfin" +#define MQTT_TOPIC_RFLEARN "rflearn" +#define MQTT_TOPIC_RFRAW "rfraw" +#define MQTT_TOPIC_UARTIN "uartin" +#define MQTT_TOPIC_UARTOUT "uartout" +#define MQTT_TOPIC_LOADAVG "loadavg" +#define MQTT_TOPIC_BOARD "board" +#define MQTT_TOPIC_PULSE "pulse" // Light module -#define MQTT_TOPIC_CHANNEL "channel" -#define MQTT_TOPIC_COLOR "color" // DEPRECATED, use RGB instead -#define MQTT_TOPIC_COLOR_RGB "rgb" -#define MQTT_TOPIC_COLOR_HSV "hsv" -#define MQTT_TOPIC_ANIM_MODE "anim_mode" -#define MQTT_TOPIC_ANIM_SPEED "anim_speed" -#define MQTT_TOPIC_BRIGHTNESS "brightness" -#define MQTT_TOPIC_MIRED "mired" -#define MQTT_TOPIC_KELVIN "kelvin" - -#define MQTT_STATUS_ONLINE "1" // Value for the device ON message -#define MQTT_STATUS_OFFLINE "0" // Value for the device OFF message (will) - -#define MQTT_ACTION_RESET "reboot" // RESET MQTT topic particle - -// Internal MQTT events (do not change) -#define MQTT_CONNECT_EVENT 0 -#define MQTT_DISCONNECT_EVENT 1 -#define MQTT_MESSAGE_EVENT 2 +#define MQTT_TOPIC_CHANNEL "channel" +#define MQTT_TOPIC_COLOR_RGB "rgb" +#define MQTT_TOPIC_COLOR_HSV "hsv" +#define MQTT_TOPIC_ANIM_MODE "anim_mode" +#define MQTT_TOPIC_ANIM_SPEED "anim_speed" +#define MQTT_TOPIC_BRIGHTNESS "brightness" +#define MQTT_TOPIC_MIRED "mired" +#define MQTT_TOPIC_KELVIN "kelvin" + +#define MQTT_STATUS_ONLINE "1" // Value for the device ON message +#define MQTT_STATUS_OFFLINE "0" // Value for the device OFF message (will) + +#define MQTT_ACTION_RESET "reboot" // RESET MQTT topic particle + +#define MQTT_MESSAGE_ID_SHIFT 1000 // Store MQTT message id into EEPROM every these many // Custom get and set postfixes // Use something like "/status" or "/set", with leading slash // Since 1.9.0 the default value is "" for getter and "/set" for setter -#define MQTT_USE_GETTER "" -#define MQTT_USE_SETTER "/set" +#ifndef MQTT_GETTER +#define MQTT_GETTER "" +#endif + +#ifndef MQTT_SETTER +#define MQTT_SETTER "/set" +#endif + +// ----------------------------------------------------------------------------- +// BROKER +// ----------------------------------------------------------------------------- + +#ifndef BROKER_SUPPORT +#define BROKER_SUPPORT 1 // The broker is a poor-man's pubsub manager +#endif // ----------------------------------------------------------------------------- // SETTINGS @@ -504,12 +736,6 @@ PROGMEM const char* const custom_reset_string[] = { // LIGHT // ----------------------------------------------------------------------------- -// Available light providers (do not change) -#define LIGHT_PROVIDER_NONE 0 -#define LIGHT_PROVIDER_MY92XX 1 // works with MY9291 and MY9231 -#define LIGHT_PROVIDER_DIMMER 2 -#define LIGHT_PROVIDER_FASTLED 3 - // LIGHT_PROVIDER_DIMMER can have from 1 to 5 different channels. // They have to be defined for each device in the hardware.h file. // If 3 or more channels first 3 will be considered RGB. @@ -524,7 +750,10 @@ PROGMEM const char* const custom_reset_string[] = { #define LIGHT_SAVE_ENABLED 1 // Light channel values saved by default after each change #endif +#ifndef LIGHT_SAVE_DELAY #define LIGHT_SAVE_DELAY 5 // Persist color after 5 seconds to avoid wearing out +#endif + #ifndef LIGHT_MAX_PWM #define LIGHT_MAX_PWM 255 @@ -542,17 +771,64 @@ PROGMEM const char* const custom_reset_string[] = { #define LIGHT_MAX_VALUE 255 // Maximum light value #endif +#ifndef LIGHT_MAX_BRIGHTNESS #define LIGHT_MAX_BRIGHTNESS 255 // Maximun brightness value +#endif + +#define LIGHT_MIN_MIREDS 153 // Default to the Philips Hue value that HA also use. +#define LIGHT_MAX_MIREDS 500 // https://developers.meethue.com/documentation/core-concepts + +#ifndef LIGHT_STEP #define LIGHT_STEP 32 // Step size +#endif + +#ifndef LIGHT_USE_COLOR #define LIGHT_USE_COLOR 1 // Use 3 first channels as RGB -#define LIGHT_USE_WHITE 0 // Use white channel whenever RGB have the same value +#endif + +#ifndef LIGHT_USE_WHITE +#define LIGHT_USE_WHITE 0 // Use the 4th channel as (Warm-)White LEDs +#endif + +#ifndef LIGHT_USE_CCT +#define LIGHT_USE_CCT 0 // Use the 5th channel as Coldwhite LEDs, LIGHT_USE_WHITE must be 1. +#endif + +// Used when LIGHT_USE_WHITE AND LIGHT_USE_CCT is 1 - (1000000/Kelvin = MiReds) +// Warning! Don't change this yet, NOT FULLY IMPLEMENTED! +#define LIGHT_COLDWHITE_MIRED 153 // Coldwhite Strip, Value must be __BELOW__ W2!! (Default: 6535 Kelvin/153 MiRed) +#define LIGHT_WARMWHITE_MIRED 500 // Warmwhite Strip, Value must be __ABOVE__ W1!! (Default: 2000 Kelvin/500 MiRed) + +#ifndef LIGHT_USE_GAMMA #define LIGHT_USE_GAMMA 0 // Use gamma correction for color channels +#endif + +#ifndef LIGHT_USE_CSS #define LIGHT_USE_CSS 1 // Use CSS style to report colors (1=> "#FF0000", 0=> "255,0,0") +#endif + +#ifndef LIGHT_USE_RGB #define LIGHT_USE_RGB 0 // Use RGB color selector (1=> RGB, 0=> HSV) +#endif + +#ifndef LIGHT_WHITE_FACTOR +#define LIGHT_WHITE_FACTOR 1 // When using LIGHT_USE_WHITE with uneven brightness LEDs, + // this factor is used to scale the white channel to match brightness +#endif + +#ifndef LIGHT_USE_TRANSITIONS #define LIGHT_USE_TRANSITIONS 1 // Transitions between colors +#endif + +#ifndef LIGHT_TRANSITION_STEP #define LIGHT_TRANSITION_STEP 10 // Time in millis between each transtion step -#define LIGHT_TRANSITION_STEPS 50 // Number of steps to acomplish transition +#endif + +#ifndef LIGHT_TRANSITION_TIME +#define LIGHT_TRANSITION_TIME 500 // Time in millis from color to color +#endif + // ----------------------------------------------------------------------------- @@ -590,7 +866,6 @@ PROGMEM const char* const custom_reset_string[] = { #define DOMOTICZ_ENABLED 0 // Disable domoticz by default #define DOMOTICZ_IN_TOPIC "domoticz/in" // Default subscription topic #define DOMOTICZ_OUT_TOPIC "domoticz/out" // Default publication topic -#define DOMOTICZ_SKIP_TIME 2 // Avoid recursion skipping messages to same IDX within 2 seconds // ----------------------------------------------------------------------------- // HOME ASSISTANT @@ -608,82 +883,180 @@ PROGMEM const char* const custom_reset_string[] = { // ----------------------------------------------------------------------------- #ifndef INFLUXDB_SUPPORT -#define INFLUXDB_SUPPORT 0 // Enable InfluxDB support by default (4.38Kb) +#define INFLUXDB_SUPPORT 0 // Disable InfluxDB support by default (4.38Kb) #endif +#ifndef INFLUXDB_ENABLED #define INFLUXDB_ENABLED 0 // InfluxDB disabled by default +#endif + +#ifndef INFLUXDB_HOST #define INFLUXDB_HOST "" // Default server +#endif + +#ifndef INFLUXDB_PORT #define INFLUXDB_PORT 8086 // Default InfluxDB port +#endif + +#ifndef INFLUXDB_DATABASE #define INFLUXDB_DATABASE "" // Default database +#endif + +#ifndef INFLUXDB_USERNAME #define INFLUXDB_USERNAME "" // Default username +#endif + +#ifndef INFLUXDB_PASSWORD #define INFLUXDB_PASSWORD "" // Default password +#endif + + +// ----------------------------------------------------------------------------- +// THINGSPEAK +// ----------------------------------------------------------------------------- + +#ifndef THINGSPEAK_SUPPORT +#define THINGSPEAK_SUPPORT 1 // Enable Thingspeak support by default (2.56Kb) +#endif + +#ifndef THINGSPEAK_ENABLED +#define THINGSPEAK_ENABLED 0 // Thingspeak disabled by default +#endif + +#ifndef THINGSPEAK_APIKEY +#define THINGSPEAK_APIKEY "" // Default API KEY +#endif + +#define THINGSPEAK_USE_ASYNC 1 // Use AsyncClient instead of WiFiClientSecure + +// THINGSPEAK OVER SSL +// Using THINGSPEAK over SSL works well but generates problems with the web interface, +// so you should compile it with WEB_SUPPORT to 0. +// When THINGSPEAK_USE_ASYNC is 1, requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0. +#define THINGSPEAK_USE_SSL 0 // Use secure connection + +#define THINGSPEAK_FINGERPRINT "78 60 18 44 81 35 BF DF 77 84 D4 0A 22 0D 9B 4E 6C DC 57 2C" + +#define THINGSPEAK_HOST "api.thingspeak.com" +#if THINGSPEAK_USE_SSL +#define THINGSPEAK_PORT 443 +#else +#define THINGSPEAK_PORT 80 +#endif + +#define THINGSPEAK_URL "/update" + +#define THINGSPEAK_MIN_INTERVAL 15000 // Minimum interval between POSTs (in millis) + +// ----------------------------------------------------------------------------- +// SCHEDULER +// ----------------------------------------------------------------------------- + +#ifndef SCHEDULER_SUPPORT +#define SCHEDULER_SUPPORT 1 // Enable scheduler (1.77Kb) +#endif + +#ifndef SCHEDULER_MAX_SCHEDULES +#define SCHEDULER_MAX_SCHEDULES 10 // Max schedules alowed +#endif // ----------------------------------------------------------------------------- // NTP // ----------------------------------------------------------------------------- #ifndef NTP_SUPPORT -#define NTP_SUPPORT 1 // Build with NTP support by default (6.78Kb) +#define NTP_SUPPORT 1 // Build with NTP support by default (6.78Kb) +#endif + +#ifndef NTP_SERVER +#define NTP_SERVER "pool.ntp.org" // Default NTP server +#endif + +#ifndef NTP_TIMEOUT +#define NTP_TIMEOUT 1000 // Set NTP request timeout to 2 seconds (issue #452) +#endif + +#ifndef NTP_TIME_OFFSET +#define NTP_TIME_OFFSET 60 // Default timezone offset (GMT+1) +#endif + +#ifndef NTP_DAY_LIGHT +#define NTP_DAY_LIGHT 1 // Enable daylight time saving by default +#endif + +#ifndef NTP_SYNC_INTERVAL +#define NTP_SYNC_INTERVAL 60 // NTP initial check every minute #endif -#define NTP_SERVER "pool.ntp.org" // Default NTP server -#define NTP_TIME_OFFSET 1 // Default timezone offset (GMT+1) -#define NTP_DAY_LIGHT true // Enable daylight time saving by default -#define NTP_UPDATE_INTERVAL 1800 // NTP check every 30 minutes +#ifndef NTP_UPDATE_INTERVAL +#define NTP_UPDATE_INTERVAL 1800 // NTP check every 30 minutes +#endif + +#ifndef NTP_START_DELAY +#define NTP_START_DELAY 1000 // Delay NTP start 1 second +#endif + +#ifndef NTP_DST_REGION +#define NTP_DST_REGION 0 // 0 for Europe, 1 for USA (defined in NtpClientLib) +#endif // ----------------------------------------------------------------------------- -// FAUXMO +// ALEXA // ----------------------------------------------------------------------------- // This setting defines whether Alexa support should be built into the firmware #ifndef ALEXA_SUPPORT -#define ALEXA_SUPPORT 1 // Enable Alexa support by default (9.5Kb) +#define ALEXA_SUPPORT 1 // Enable Alexa support by default (10.84Kb) #endif // This is default value for the alexaEnabled setting that defines whether // this device should be discoberable and respond to Alexa commands. // Both ALEXA_SUPPORT and alexaEnabled should be 1 for Alexa support to work. -#define ALEXA_ENABLED 1 +#ifndef ALEXA_ENABLED +#define ALEXA_ENABLED 1 +#endif // ----------------------------------------------------------------------------- // RFBRIDGE +// This module is not compatible with RF_SUPPORT=1 // ----------------------------------------------------------------------------- -#define RF_SEND_TIMES 4 // How many times to send the message -#define RF_SEND_DELAY 500 // Interval between sendings in ms -#define RF_RECEIVE_DELAY 500 // Interval between recieving in ms (avoid debouncing) +#ifndef RF_SEND_TIMES +#define RF_SEND_TIMES 4 // How many times to send the message +#endif + +#ifndef RF_SEND_DELAY +#define RF_SEND_DELAY 500 // Interval between sendings in ms +#endif + +#ifndef RF_RECEIVE_DELAY +#define RF_RECEIVE_DELAY 500 // Interval between recieving in ms (avoid debouncing) +#endif + + +#ifndef RF_RAW_SUPPORT +#define RF_RAW_SUPPORT 0 // RF raw codes require a specific firmware for the EFM8BB1 + // https://github.com/rhx/RF-Bridge-EFM8BB1 +#endif + // ----------------------------------------------------------------------------- // IR // ----------------------------------------------------------------------------- #ifndef IR_SUPPORT -#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 #ifndef IR_PIN -#define IR_PIN 4 // IR LED +#define IR_PIN 4 // IR LED #endif // 24 Buttons Set of the IR Remote #ifndef IR_BUTTON_SET -#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 -// IR Button modes -#define IR_BUTTON_MODE_NONE 0 -#define IR_BUTTON_MODE_RGB 1 -#define IR_BUTTON_MODE_HSV 2 -#define IR_BUTTON_MODE_BRIGHTER 3 -#define IR_BUTTON_MODE_STATE 4 -#define IR_BUTTON_MODE_EFFECT 5 - -#define LIGHT_EFFECT_SOLID 0 -#define LIGHT_EFFECT_FLASH 1 -#define LIGHT_EFFECT_STROBE 2 -#define LIGHT_EFFECT_FADE 3 -#define LIGHT_EFFECT_SMOOTH 4 - //Remote Buttons SET 1 (for the original Remote shipped with the controller) #if IR_SUPPORT #if IR_BUTTON_SET == 1 @@ -799,12 +1172,45 @@ PROGMEM const char* const custom_reset_string[] = { #endif +//Remote Buttons SET 3 (samsung AA59-00608A 8 Toggle Buttons for generic 8CH module) +#if IR_BUTTON_SET == 3 +/* + +------+------+------+ + | 1 | 2 | 3 | + +------+------+------+ + | 4 | 5 | 6 | + +------+------+------+ + | 7 | 8 | 9 | + +------+------+------+ + | | 0 | | + +------+------+------+ +*/ +#define IR_BUTTON_COUNT 10 + + const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = { + + { 0xE0E020DF, IR_BUTTON_MODE_TOGGLE, 0 }, // Toggle Relay #0 + { 0xE0E0A05F, IR_BUTTON_MODE_TOGGLE, 1 }, // Toggle Relay #1 + { 0xE0E0609F, IR_BUTTON_MODE_TOGGLE, 2 }, // Toggle Relay #2 + + { 0xE0E010EF, IR_BUTTON_MODE_TOGGLE, 3 }, // Toggle Relay #3 + { 0xE0E0906F, IR_BUTTON_MODE_TOGGLE, 4 }, // Toggle Relay #4 + { 0xE0E050AF, IR_BUTTON_MODE_TOGGLE, 5 }, // Toggle Relay #5 + + { 0xE0E030CF, IR_BUTTON_MODE_TOGGLE, 6 }, // Toggle Relay #6 + { 0xE0E0B04F, IR_BUTTON_MODE_TOGGLE, 7 } // Toggle Relay #7 + //{ 0xE0E0708F, IR_BUTTON_MODE_TOGGLE, 8 } //Extra Button + + //{ 0xE0E08877, IR_BUTTON_MODE_TOGGLE, 9 } //Extra Button + }; +#endif #endif // IR_SUPPORT //-------------------------------------------------------------------------------- // Custom RF module // Check http://tinkerman.cat/adding-rf-to-a-non-rf-itead-sonoff/ // Enable support by passing RF_SUPPORT=1 build flag +// This module is not compatible with RFBRIDGE or SONOFF RF //-------------------------------------------------------------------------------- #ifndef RF_SUPPORT @@ -815,5 +1221,5 @@ PROGMEM const char* const custom_reset_string[] = { #define RF_PIN 14 #endif -#define RF_CHANNEL 31 -#define RF_DEVICE 1 +#define RF_DEBOUNCE 500 +#define RF_LEARN_TIMEOUT 60000 diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h index 27b90757..c8e5c5c1 100644 --- a/code/espurna/config/hardware.h +++ b/code/espurna/config/hardware.h @@ -11,20 +11,47 @@ // - BUTTON_SWITCH: button event is fired when pressed or released // - BUTTON_DEFAULT_HIGH: there is a pull up in place // - BUTTON_SET_PULLUP: set pullup by software -// RELAY#_PIN: GPIO for the n-th relay (1-based, up to 4 relays) -// RELAY#_TYPE: Relay can be RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE or RELAY_TYPE_LATCHED -// LED#_PIN: GPIO for the n-th LED (1-based, up to 4 LEDs) +// RELAY#_PIN: GPIO for the n-th relay (1-based, up to 8 relays) +// RELAY#_TYPE: Relay can be RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE, RELAY_TYPE_LATCHED or RELAY_TYPE_LATCHED_INVERSE +// LED#_PIN: GPIO for the n-th LED (1-based, up to 8 LEDs) // LED#_PIN_INVERSE: LED has inversed logic (lit when pulled down) -// LED#_MODE: Check hardware.h for LED_MODE_% +// LED#_MODE: Check general.h for LED_MODE_% // LED#_RELAY: Linked relay (1-based) // // Besides, other hardware specific information should be stated here +// ----------------------------------------------------------------------------- +// ESPurna Core +// ----------------------------------------------------------------------------- + +#if defined(ESPURNA_CORE) + + // This is a special device targeted to generate a light-weight binary image + // meant to be able to do two-step-updates: + // https://github.com/xoseperez/espurna/wiki/TwoStepUpdates + + // Info + #define MANUFACTURER "ESPRESSIF" + #define DEVICE "ESPURNA_CORE" + + // Disable non-core modules + #define ALEXA_SUPPORT 0 + #define BROKER_SUPPORT 0 + #define DOMOTICZ_SUPPORT 0 + #define HOMEASSISTANT_SUPPORT 0 + #define I2C_SUPPORT 0 + #define MQTT_SUPPORT 0 + #define NTP_SUPPORT 0 + #define SCHEDULER_SUPPORT 0 + #define SENSOR_SUPPORT 0 + #define THINGSPEAK_SUPPORT 0 + #define WEB_SUPPORT 0 + // ----------------------------------------------------------------------------- // Development boards // ----------------------------------------------------------------------------- -#if defined(NODEMCU_LOLIN) +#elif defined(NODEMCU_LOLIN) // Info #define MANUFACTURER "NODEMCU" @@ -43,6 +70,12 @@ #define LED1_PIN 2 #define LED1_PIN_INVERSE 1 +#elif defined(NODEMCU_BASIC) + // Info + // Generic NodeMCU Board without any buttons or relays connected. + #define MANUFACTURER "NODEMCU" + #define DEVICE "BASIC" + #elif defined(WEMOS_D1_MINI_RELAYSHIELD) // Info @@ -64,31 +97,16 @@ #define LED1_PIN 2 #define LED1_PIN_INVERSE 1 -#elif defined(GENERIC_FASTLED) - - // Info - #define MANUFACTURER "GENERIC" - #define DEVICE "FASTLED" - - // Buttons - #define BUTTON1_PIN 13 // 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 | BUTTON_SET_PULLUP - #define BUTTON1_RELAY 1 - - // Relays - #define RELAY_PROVIDER RELAY_PROVIDER_LIGHT - #define DUMMY_RELAY_COUNT 1 + // When Wemos relay shield is connected GPIO5 (D1) is used for relay, + // so I2C must be remapped to other pins + #define I2C_SDA_PIN 12 // D6 + #define I2C_SCL_PIN 14 // D5 - // LEDs - #define LED1_PIN 2 - #define LED1_PIN_INVERSE 1 +#elif defined(WEMOS_D1_TARPUNA_SHIELD) - #define LIGHT_PROVIDER LIGHT_PROVIDER_FASTLED - #define LIGHT_FASTLED_TYPE WS2812B - #define LIGHT_FASTLED_ORDER RGB - #define LIGHT_FASTLED_NUM 41 - #define LIGHT_FASTLED_DATA_PIN 5 + // Info + #define MANUFACTURER "WEMOS" + #define DEVICE "D1_TARPUNA_SHIELD" // ----------------------------------------------------------------------------- // ESPurna @@ -193,7 +211,7 @@ #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH #define BUTTON1_RELAY 1 #define BUTTON2_PIN 14 - #define BUTTON2_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP + #define BUTTON2_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH #define BUTTON2_RELAY 1 // Relays @@ -215,7 +233,7 @@ #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH #define BUTTON1_RELAY 1 #define BUTTON2_PIN 14 - #define BUTTON2_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP + #define BUTTON2_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH #define BUTTON2_RELAY 1 // Relays @@ -367,6 +385,34 @@ #define HLW8012_CF1_PIN 13 #define HLW8012_CF_PIN 14 +#elif defined(ITEAD_SONOFF_POW_R2) + + // Info + #define MANUFACTURER "ITEAD" + #define DEVICE "SONOFF_POW_R2" + + // Buttons + #define BUTTON1_PIN 0 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 12 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 13 + #define LED1_PIN_INVERSE 1 + + // Disable UART noise + #define DEBUG_SERIAL_SUPPORT 0 + + // CSE7766 + #ifndef CSE7766_SUPPORT + #define CSE7766_SUPPORT 1 + #endif + #define CSE7766_PIN 1 + #elif defined(ITEAD_SONOFF_DUAL) // Info @@ -376,7 +422,6 @@ #define RELAY_PROVIDER RELAY_PROVIDER_DUAL #define DUMMY_RELAY_COUNT 2 #define DEBUG_SERIAL_SUPPORT 0 - #define TERMINAL_SUPPORT 0 // Buttons #define BUTTON3_RELAY 1 @@ -391,14 +436,14 @@ #define DEVICE "SONOFF_DUAL_R2" // Buttons - #define BUTTON1_PIN 0 - #define BUTTON2_PIN 9 - #define BUTTON3_PIN 10 + #define BUTTON1_PIN 0 // Button 0 on header + #define BUTTON2_PIN 9 // Button 1 on header + #define BUTTON3_PIN 10 // Physical button #define BUTTON1_RELAY 1 #define BUTTON2_RELAY 2 #define BUTTON3_RELAY 1 - #define BUTTON1_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP - #define BUTTON2_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP + #define BUTTON1_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH + #define BUTTON2_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH #define BUTTON3_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH // Relays @@ -470,6 +515,39 @@ #define BUTTON3_RELAY 3 #define BUTTON4_RELAY 4 + // Sonoff 4CH Pro uses a secondary STM32 microcontroller to handle + // buttons and relays, but it also forwards button presses to the ESP8285. + // This allows ESPurna to handle button presses -almost- the same way + // as with other devices except: + // * Double click seems to break/disable the button on the STM32 side + // * With S6 switch to 1 (self-locking and inching modes) everything's OK + // * With S6 switch to 0 (interlock mode) if there is a relay ON + // and you click on another relay button, the STM32 sends a "press" + // event for the button of the first relay (to turn it OFF) but it + // does not send a "release" event. It's like it's holding the + // button down since you can see it is still LOW. + // Whatever reason the result is that it may actually perform a + // long click or long-long click. + // The configuration below make the button toggle the relay on press events + // and disables any possibly harmful combination with S6 set to 0. + // If you are sure you will only use S6 to 1 you can comment the + // BUTTON1_LNGCLICK and BUTTON1_LNGLNGCLICK options below to recover the + // reset mode and factory reset functionalities, or link other actions like + // AP mode in the commented line below. + + #define BUTTON1_PRESS BUTTON_MODE_TOGGLE + #define BUTTON1_CLICK BUTTON_MODE_NONE + #define BUTTON1_DBLCLICK BUTTON_MODE_NONE + #define BUTTON1_LNGCLICK BUTTON_MODE_NONE + //#define BUTTON1_LNGCLICK BUTTON_MODE_AP + #define BUTTON1_LNGLNGCLICK BUTTON_MODE_NONE + #define BUTTON2_PRESS BUTTON_MODE_TOGGLE + #define BUTTON2_CLICK BUTTON_MODE_NONE + #define BUTTON3_PRESS BUTTON_MODE_TOGGLE + #define BUTTON3_CLICK BUTTON_MODE_NONE + #define BUTTON4_PRESS BUTTON_MODE_TOGGLE + #define BUTTON4_CLICK BUTTON_MODE_NONE + // Relays #define RELAY1_PIN 12 #define RELAY2_PIN 5 @@ -555,17 +633,13 @@ // Info #define MANUFACTURER "ITEAD" #define DEVICE "SONOFF_RFBRIDGE" - #define SERIAL_BAUDRATE 19200 #define RELAY_PROVIDER RELAY_PROVIDER_RFBRIDGE + // Number of virtual switches #ifndef DUMMY_RELAY_COUNT #define DUMMY_RELAY_COUNT 8 #endif - // Remove UART noise on serial line - #define TERMINAL_SUPPORT 0 - #define DEBUG_SERIAL_SUPPORT 0 - // Buttons #define BUTTON1_PIN 0 #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH @@ -574,6 +648,28 @@ #define LED1_PIN 13 #define LED1_PIN_INVERSE 1 + // RFB Direct hack thanks to @wildwiz + // https://github.com/xoseperez/espurna/wiki/Hardware-Itead-Sonoff-RF-Bridge---Direct-Hack + #ifndef RFB_DIRECT + #define RFB_DIRECT 0 + #endif + + #ifndef RFB_RX_PIN + #define RFB_RX_PIN 4 // GPIO for RX when RFB_DIRECT + #endif + + #ifndef RFB_TX_PIN + #define RFB_TX_PIN 5 // GPIO for TX when RFB_DIRECT + #endif + + // When using un-modified harware, ESPurna communicates with the secondary + // MCU EFM8BB1 via UART at 19200 bps so we need to change the speed of + // the port and remove UART noise on serial line + #if not RFB_DIRECT + #define SERIAL_BAUDRATE 19200 + #define DEBUG_SERIAL_SUPPORT 0 + #endif + #elif defined(ITEAD_SONOFF_B1) // Info @@ -591,6 +687,7 @@ #define MY92XX_DCKI_PIN 14 #define MY92XX_COMMAND MY92XX_COMMAND_DEFAULT #define MY92XX_MAPPING 4, 3, 5, 0, 1 + #define LIGHT_WHITE_FACTOR (0.1) // White LEDs are way more bright in the B1 #elif defined(ITEAD_SONOFF_LED) @@ -723,6 +820,31 @@ #define LED1_PIN 13 #define LED1_PIN_INVERSE 1 +#elif defined(ITEAD_SONOFF_S31) + + // Info + #define MANUFACTURER "ITEAD" + #define DEVICE "SONOFF_S31" + + // Buttons + #define BUTTON1_PIN 0 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 12 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 13 + #define LED1_PIN_INVERSE 1 + + // Disable UART noise + #define DEBUG_SERIAL_SUPPORT 0 + + // CSE7766 + #define CSE7766_SUPPORT 1 + #define CSE7766_PIN 1 // ----------------------------------------------------------------------------- // YJZK @@ -754,7 +876,6 @@ // LEDs #define LED1_PIN 13 #define LED1_PIN_INVERSE 0 - #define LED_WIFI 0 // ----------------------------------------------------------------------------- @@ -908,6 +1029,7 @@ #define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER #define DUMMY_RELAY_COUNT 1 #define DEBUG_PORT Serial1 + #define SERIAL_RX_ENABLED 1 // LEDs #define LED1_PIN 5 @@ -935,6 +1057,7 @@ #define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER #define DUMMY_RELAY_COUNT 1 #define DEBUG_PORT Serial1 + #define SERIAL_RX_ENABLED 1 // Light #define LIGHT_CHANNELS 4 @@ -1151,7 +1274,7 @@ #define RELAY1_TYPE RELAY_TYPE_NORMAL #define RELAY2_TYPE RELAY_TYPE_NORMAL - // DB18B20 + // DS18B20 #ifndef DALLAS_SUPPORT #define DALLAS_SUPPORT 1 #endif @@ -1198,16 +1321,33 @@ #define DUMMY_RELAY_COUNT 1 // Light - #define LIGHT_CHANNELS 4 + #define LIGHT_CHANNELS 3 #define LIGHT_CH1_PIN 5 // RED #define LIGHT_CH2_PIN 12 // GREEN #define LIGHT_CH3_PIN 13 // BLUE - #define LIGHT_CH4_PIN 14 // WHITE1 #define LIGHT_CH1_INVERSE 0 #define LIGHT_CH2_INVERSE 0 #define LIGHT_CH3_INVERSE 0 - #define LIGHT_CH4_INVERSE 0 +#elif defined(ARILUX_AL_LC02) + + // Info + #define MANUFACTURER "ARILUX" + #define DEVICE "AL_LC02" + #define RELAY_PROVIDER RELAY_PROVIDER_LIGHT + #define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER + #define DUMMY_RELAY_COUNT 1 + + // Light + #define LIGHT_CHANNELS 4 + #define LIGHT_CH1_PIN 12 // RED + #define LIGHT_CH2_PIN 5 // GREEN + #define LIGHT_CH3_PIN 13 // BLUE + #define LIGHT_CH4_PIN 15 // WHITE1 + #define LIGHT_CH1_INVERSE 0 + #define LIGHT_CH2_INVERSE 0 + #define LIGHT_CH3_INVERSE 0 + #define LIGHT_CH4_INVERSE 0 #elif defined(ARILUX_AL_LC06) @@ -1231,7 +1371,6 @@ #define LIGHT_CH4_INVERSE 0 #define LIGHT_CH5_INVERSE 0 - #elif defined(ARILUX_AL_LC11) // Info @@ -1254,7 +1393,6 @@ #define LIGHT_CH4_INVERSE 0 #define LIGHT_CH5_INVERSE 0 - #elif defined(ARILUX_E27) // Info @@ -1323,6 +1461,104 @@ #define LIGHT_ENABLE_PIN 15 +#elif defined(GIZWITS_WITTY_CLOUD) + + // Info + #define MANUFACTURER "GIZWITS" + #define DEVICE "WITTY_CLOUD" + #define RELAY_PROVIDER RELAY_PROVIDER_LIGHT + #define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER + #define DUMMY_RELAY_COUNT 1 + + // Buttons + #define BUTTON1_PIN 4 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_PRESS BUTTON_MODE_TOGGLE + #define BUTTON1_CLICK BUTTON_MODE_NONE + #define BUTTON1_DBLCLICK BUTTON_MODE_NONE + #define BUTTON1_LNGCLICK BUTTON_MODE_NONE + #define BUTTON1_LNGLNGCLICK BUTTON_MODE_RESET + + #define ANALOG_SUPPORT 1 + + // LEDs + #define LED1_PIN 2 // BLUE build-in + #define LED1_PIN_INVERSE 1 + + // Light + #define LIGHT_CHANNELS 3 + #define LIGHT_CH1_PIN 15 // RED + #define LIGHT_CH2_PIN 12 // GREEN + #define LIGHT_CH3_PIN 13 // BLUE + #define LIGHT_CH1_INVERSE 0 + #define LIGHT_CH2_INVERSE 0 + #define LIGHT_CH3_INVERSE 0 + +// ----------------------------------------------------------------------------- +// KMC 70011 +// https://www.amazon.com/KMC-Monitoring-Required-Control-Compatible/dp/B07313TH7B +// ----------------------------------------------------------------------------- + +#elif defined(KMC_70011) + + // Info + #define MANUFACTURER "KMC" + #define DEVICE "70011" + + // Buttons + #define BUTTON1_PIN 0 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 14 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 13 + #define LED1_PIN_INVERSE 0 + + // HLW8012 + #ifndef HLW8012_SUPPORT + #define HLW8012_SUPPORT 1 + #endif + #define HLW8012_SEL_PIN 12 + #define HLW8012_CF1_PIN 5 + #define HLW8012_CF_PIN 4 + + #define HLW8012_VOLTAGE_R_UP ( 2 * 1000000 ) // Upstream voltage resistor + +// ----------------------------------------------------------------------------- +// Euromate (?) Wifi Stecker Shuko +// https://www.obi.de/hausfunksteuerung/wifi-stecker-schuko/p/2291706 +// Thanks to @Geitde +// ----------------------------------------------------------------------------- + +#elif defined(EUROMATE_WIFI_STECKER_SCHUKO) + + // Info + #define MANUFACTURER "EUROMATE" + #define DEVICE "WIFI_STECKER_SCHUKO" + + // Buttons + #define BUTTON1_PIN 14 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // The relay in the device is not a bistable (latched) relay. + // The device is reported to have a flip-flop circuit to drive the relay + // So @Geitde hack is still the only possible + + // Hack: drive GPIO12 low and use GPIO5 as normal relay pin: + #define RELAY1_PIN 5 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + #define LED2_PIN 12 /* DUMMY: exploit default off state for GPIO12=low */ + #define LED2_PIN_INVERSE 0 + + // LEDs + #define LED1_PIN 4 + #define LED1_PIN_INVERSE 0 + // ----------------------------------------------------------------------------- // Generic 8CH // ----------------------------------------------------------------------------- @@ -1352,9 +1588,851 @@ #define RELAY8_TYPE RELAY_TYPE_NORMAL // ----------------------------------------------------------------------------- -// Unknown hardware +// STM RELAY +// ----------------------------------------------------------------------------- + +#elif defined(STM_RELAY) + + // Info + #define MANUFACTURER "STM_RELAY" + #define DEVICE "2CH" + + // Relays + #define DUMMY_RELAY_COUNT 2 + #define RELAY_PROVIDER RELAY_PROVIDER_STM + + // Remove UART noise on serial line + #define DEBUG_SERIAL_SUPPORT 0 + +// ----------------------------------------------------------------------------- +// Tonbux Powerstrip02 +// ----------------------------------------------------------------------------- + +#elif defined(TONBUX_POWERSTRIP02) + + // Info + #define MANUFACTURER "TONBUX" + #define DEVICE "POWERSTRIP02" + + // Buttons + #define BUTTON1_PIN 5 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 0 + + // Relays + #define RELAY1_PIN 4 + #define RELAY1_TYPE RELAY_TYPE_INVERSE + #define RELAY2_PIN 13 + #define RELAY2_TYPE RELAY_TYPE_INVERSE + #define RELAY3_PIN 12 + #define RELAY3_TYPE RELAY_TYPE_INVERSE + #define RELAY4_PIN 14 + #define RELAY4_TYPE RELAY_TYPE_INVERSE + // Not a relay. USB ports on/off + #define RELAY5_PIN 16 + #define RELAY5_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 0 // 1 blue led + #define LED1_PIN_INVERSE 1 + #define LED2_PIN 3 // 3 red leds + #define LED2_PIN_INVERSE 1 + +// ----------------------------------------------------------------------------- +// Lingan SWA1 +// ----------------------------------------------------------------------------- + +#elif defined(LINGAN_SWA1) + + // Info + #define MANUFACTURER "LINGAN" + #define DEVICE "SWA1" + + // Buttons + #define BUTTON1_PIN 13 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 5 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 4 + #define LED1_PIN_INVERSE 1 + +// ----------------------------------------------------------------------------- +// HEYGO HY02 +// ----------------------------------------------------------------------------- + +#elif defined(HEYGO_HY02) + + // Info + #define MANUFACTURER "HEYGO" + #define DEVICE "HY02" + + // Buttons + #define BUTTON1_PIN 13 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 12 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 4 + #define LED1_PIN_INVERSE 0 + +// ----------------------------------------------------------------------------- +// Maxcio W-US002S +// ----------------------------------------------------------------------------- + +#elif defined(MAXCIO_WUS002S) + + // Info + #define MANUFACTURER "MAXCIO" + #define DEVICE "WUS002S" + + // Buttons + #define BUTTON1_PIN 2 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 13 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 3 + #define LED1_PIN_INVERSE 0 + + // HLW8012 + #ifndef HLW8012_SUPPORT + #define HLW8012_SUPPORT 1 + #endif + #define HLW8012_SEL_PIN 12 + #define HLW8012_CF1_PIN 5 + #define HLW8012_CF_PIN 4 + + #define HLW8012_CURRENT_R 0.002 // Current resistor + #define HLW8012_VOLTAGE_R_UP ( 2 * 1000000 ) // Upstream voltage resistor + +// ----------------------------------------------------------------------------- +// YiDian XS-SSA05 +// ----------------------------------------------------------------------------- + +#elif defined(YIDIAN_XSSSA05) + + // Info + #define MANUFACTURER "YIDIAN" + #define DEVICE "XSSSA05" + + // Buttons + #define BUTTON1_PIN 13 + #define BUTTON1_MODE BUTTON_PUSHBUTTON + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 12 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 4 + #define LED1_PIN_INVERSE 0 + + // HLW8012 + #ifndef HLW8012_SUPPORT + #define HLW8012_SUPPORT 1 + #endif + #define HLW8012_SEL_PIN 3 + #define HLW8012_CF1_PIN 14 + #define HLW8012_CF_PIN 5 + + #define HLW8012_CURRENT_R 0.001 // Current resistor + #define HLW8012_VOLTAGE_R_UP ( 2 * 1200000 ) // Upstream voltage resistor + +// ----------------------------------------------------------------------------- +// TONBUX XS-SSA06 +// ----------------------------------------------------------------------------- + +#elif defined(TONBUX_XSSSA06) + + // Info + #define MANUFACTURER "TONBUX" + #define DEVICE "XSSSA06" + + // 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 + #define LED1_PIN 0 // R - 8 rgb led ring + #define LED1_PIN_INVERSE 0 + #define LED2_PIN 5 // G + #define LED2_PIN_INVERSE 0 + #define LED3_PIN 2 // B + #define LED3_PIN_INVERSE 0 + +// ----------------------------------------------------------------------------- +// GREEN ESP8266 RELAY MODULE +// https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180323113846&SearchText=Green+ESP8266 +// ----------------------------------------------------------------------------- + +#elif defined(GREEN_ESP8266RELAY) + + // Info + #define MANUFACTURER "GREEN" + #define DEVICE "ESP8266RELAY" + + // Buttons + // Not a button but input via Optocoupler + #define BUTTON1_PIN 5 + #define BUTTON1_MODE BUTTON_PUSHBUTTON + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 4 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 2 + #define LED1_PIN_INVERSE 1 + +// ----------------------------------------------------------------------------- +// Henrique Gravina ESPIKE +// https://github.com/Henriquegravina/Espike +// ----------------------------------------------------------------------------- + +#elif defined(IKE_ESPIKE) + + #define MANUFACTURER "IKE" + #define DEVICE "ESPIKE" + + #define BUTTON1_LNGLNGCLICK BUTTON_MODE_NONE + #define BUTTON1_LNGCLICK BUTTON_MODE_NONE + #define BUTTON1_DBLCLICK BUTTON_MODE_NONE + + #define BUTTON1_PIN 13 + #define BUTTON1_RELAY 1 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + + #define BUTTON2_PIN 12 + #define BUTTON2_RELAY 2 + #define BUTTON2_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + + #define BUTTON3_PIN 14 + #define BUTTON3_RELAY 2 + #define BUTTON3_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + + #define RELAY1_PIN 4 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + #define RELAY2_PIN 5 + #define RELAY2_TYPE RELAY_TYPE_NORMAL + + #define RELAY3_PIN 16 + #define RELAY3_TYPE RELAY_TYPE_NORMAL + + #define LED1_PIN 2 + #define LED1_PIN_INVERSE 1 + +// ----------------------------------------------------------------------------- +// SWIFITCH +// https://github.com/ArnieX/swifitch +// ----------------------------------------------------------------------------- + +#elif defined(ARNIEX_SWIFITCH) + + // Info + #define MANUFACTURER "ARNIEX" + #define DEVICE "SWIFITCH" + + // Buttons + #define BUTTON1_PIN 4 // D2 + #define BUTTON1_MODE BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + #define BUTTON1_PRESS BUTTON_MODE_NONE + #define BUTTON1_CLICK BUTTON_MODE_TOGGLE + #define BUTTON1_DBLCLICK BUTTON_MODE_NONE + #define BUTTON1_LNGCLICK BUTTON_MODE_NONE + #define BUTTON1_LNGLNGCLICK BUTTON_MODE_NONE + + // Relays + #define RELAY1_PIN 5 // D1 + #define RELAY1_TYPE RELAY_TYPE_INVERSE + + // LEDs + #define LED1_PIN 12 // D6 + #define LED1_PIN_INVERSE 1 + +// ----------------------------------------------------------------------------- +// ESP-01S RELAY v4.0 +// https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180404024035&SearchText=esp-01s+relay +// ----------------------------------------------------------------------------- + +#elif defined(GENERIC_ESP01S_RELAY_V40) + + // Info + #define MANUFACTURER "GENERIC" + #define DEVICE "ESP01S_RELAY_40" + + // Relays + #define RELAY1_PIN 0 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 2 + #define LED1_PIN_INVERSE 0 + +// ----------------------------------------------------------------------------- +// ESP-01S RGB LED v1.0 (some sold with ws2818) +// https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180404023816&SearchText=esp-01s+led+controller +// ----------------------------------------------------------------------------- + +#elif defined(GENERIC_ESP01S_RGBLED_V10) + + // Info + #define MANUFACTURER "GENERIC" + #define DEVICE "ESP01S_RGBLED_10" + + // This board is sold as RGB LED module BUT it has on board 3 pin ph2.0 connector (VCC, GPIO2, GND) + // so, if you wish, you may connect LED, BUTTON, RELAY, SENSOR etc. + + // Buttons + //#define BUTTON1_PIN 2 + + // Relays + //#define RELAY1_PIN 2 + + // LEDs + #define LED1_PIN 2 + #define LED1_PIN_INVERSE 0 + + +// ----------------------------------------------------------------------------- +// ESP-01S DHT11 v1.0 +// https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180410105907&SearchText=esp-01s+dht11 +// ----------------------------------------------------------------------------- + +#elif defined(GENERIC_ESP01S_DHT11_V10) + + // Info + #define MANUFACTURER "GENERIC" + #define DEVICE "ESP01S_DHT11_10" + + // DHT11 + #ifndef DHT_SUPPORT + #define DHT_SUPPORT 1 + #endif + #define DHT_PIN 2 + #define DHT_TYPE DHT_CHIP_DHT11 + +// ----------------------------------------------------------------------------- +// ESP-01S DS18B20 v1.0 +// https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180410105933&SearchText=esp-01s+ds18b20 +// ----------------------------------------------------------------------------- + +#elif defined(GENERIC_ESP01S_DS18B20_V10) + + // Info + #define MANUFACTURER "GENERIC" + #define DEVICE "ESP01S_DS18B20_10" + + // DB18B20 + #ifndef DALLAS_SUPPORT + #define DALLAS_SUPPORT 1 + #endif + #define DALLAS_PIN 2 + +// ----------------------------------------------------------------------------- +// ESP-DIN relay board V1 +// https://github.com/pilotak/esp_din +// ----------------------------------------------------------------------------- + +#elif defined(PILOTAK_ESP_DIN_V1) + + // Info + #define MANUFACTURER "PILOTAK" + #define DEVICE "ESP_DIN_V1" + + // Buttons + #define BUTTON1_PIN 0 + #define BUTTON1_RELAY 1 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + + // Relays + #define RELAY1_PIN 4 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + #define RELAY2_PIN 5 + #define RELAY2_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 15 + #define LED1_PIN_INVERSE 0 + + #define I2C_SDA_PIN 12 + #define I2C_SCL_PIN 13 + + #ifndef DALLAS_SUPPORT + #define DALLAS_SUPPORT 1 + #endif + #define DALLAS_PIN 2 + + #ifndef RF_SUPPORT + #define RF_SUPPORT 1 + #endif + #define RF_PIN 14 + + #ifndef DIGITAL_SUPPORT + #define DIGITAL_SUPPORT 1 + #endif + #define DIGITAL_PIN 16 + #define DIGITAL_PIN_MODE INPUT + +// ----------------------------------------------------------------------------- +// Heltec Touch Relay +// https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180408043114&SearchText=esp8266+touch+relay +// ----------------------------------------------------------------------------- + +#elif defined(HELTEC_TOUCHRELAY) + + // Info + #define MANUFACTURER "HELTEC" + #define DEVICE "TOUCH_RELAY" + + // Buttons + #define BUTTON1_PIN 14 + #define BUTTON1_RELAY 1 + #define BUTTON1_MODE BUTTON_PUSHBUTTON + + // Relays + #define RELAY1_PIN 12 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + +// ----------------------------------------------------------------------------- +// Zhilde ZLD-EU44-W +// http://www.zhilde.com/product/60705150109-805652505/EU_WiFi_Surge_Protector_Extension_Socket_4_Outlets_works_with_Amazon_Echo_Smart_Power_Strip.html +// ----------------------------------------------------------------------------- + +#elif defined(ZHILDE_EU44_W) + + // Info + #define MANUFACTURER "ZHILDE" + #define DEVICE "EU44_W" + + // Based on the reporter, this product uses GPIO1 and 3 for the button + // and onboard LED, so hardware serial should be disabled... + #define DEBUG_SERIAL_SUPPORT 0 + + // Buttons + #define BUTTON1_PIN 3 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + + // Relays + #define RELAY1_PIN 5 + #define RELAY2_PIN 4 + #define RELAY3_PIN 12 + #define RELAY4_PIN 13 + #define RELAY5_PIN 14 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + #define RELAY2_TYPE RELAY_TYPE_NORMAL + #define RELAY3_TYPE RELAY_TYPE_NORMAL + #define RELAY4_TYPE RELAY_TYPE_NORMAL + #define RELAY5_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 1 + #define LED1_PIN_INVERSE 1 + + // ----------------------------------------------------------------------------- + // Allnet 4duino ESP8266-UP-Relais + // http://www.allnet.de/de/allnet-brand/produkte/neuheiten/p/allnet-4duino-iot-wlan-relais-unterputz-esp8266-up-relais/ + // https://shop.allnet.de/fileadmin/transfer/products/148814.pdf + // ----------------------------------------------------------------------------- + +#elif defined(ALLNET_4DUINO_IOT_WLAN_RELAIS) + + // Info + #define MANUFACTURER "ALLNET" + #define DEVICE "4DUINO_IOT_WLAN_RELAIS" + + // Relays + #define RELAY1_PIN 14 + #define RELAY1_RESET_PIN 12 + #define RELAY1_TYPE RELAY_TYPE_LATCHED + + // LEDs + #define LED1_PIN 0 + #define LED1_PIN_INVERSE 1 + + // Buttons + //#define BUTTON1_PIN 0 + //#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + + // Using pins labelled as SDA & SCL as buttons + #define BUTTON2_PIN 4 + #define BUTTON2_MODE BUTTON_PUSHBUTTON + #define BUTTON2_PRESS BUTTON_MODE_TOGGLE + #define BUTTON2_CLICK BUTTON_MODE_NONE + #define BUTTON2_DBLCLICK BUTTON_MODE_NONE + #define BUTTON2_LNGCLICK BUTTON_MODE_NONE + #define BUTTON2_LNGLNGCLICK BUTTON_MODE_NONE + + #define BUTTON3_PIN 5 + #define BUTTON3_MODE BUTTON_PUSHBUTTON + + // Using pins labelled as SDA & SCL for I2C + //#define I2C_SDA_PIN 4 + //#define I2C_SCL_PIN 5 + + +// ----------------------------------------------------------------------------- +// Luani HVIO +// https://luani.de/projekte/esp8266-hvio/ +// https://luani.de/blog/esp8266-230v-io-modul/ +// ----------------------------------------------------------------------------- + +#elif defined(LUANI_HVIO) + + // Info + #define MANUFACTURER "LUANI" + #define DEVICE "HVIO" + + // Buttons + #define BUTTON1_PIN 12 + #define BUTTON1_RELAY 1 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_DBLCLICK BUTTON_MODE_NONE + + #define BUTTON2_PIN 13 + #define BUTTON2_RELAY 2 + #define BUTTON2_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + + + // Relays + #define RELAY1_PIN 4 + #define RELAY2_PIN 5 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + #define RELAY2_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 15 + #define LED1_PIN_INVERSE 0 + +// ----------------------------------------------------------------------------- +// Tonbux 50-100M Smart Mosquito Killer USB +// https://www.aliexpress.com/item/Original-Tonbux-50-100M-Smart-Mosquito-Killer-USB-Plug-No-Noise-Repellent-App-Smart-Module/32859330820.html +// ----------------------------------------------------------------------------- + +#elif defined(TONBUX_MOSQUITO_KILLER) + + // Info + #define MANUFACTURER "TONBUX" + #define DEVICE "MOSQUITO_KILLER" + + // Buttons + #define BUTTON1_PIN 2 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 5 // not a relay, fan + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 15 // blue led + #define LED1_PIN_INVERSE 1 + #define LED1_MODE LED_MODE_WIFI + #define LED2_PIN 14 // red led + #define LED2_PIN_INVERSE 1 + #define LED2_MODE LED_MODE_RELAY + + #define LED3_PIN 12 // UV leds (1-2-3-4-5-6-7-8) + #define LED3_PIN_INVERSE 0 + #define LED3_RELAY 1 + #define LED4_PIN 16 // UV leds (9-10-11) + #define LED4_PIN_INVERSE 0 + #define LED4_RELAY 1 + +// ----------------------------------------------------------------------------- +// NEO Coolcam Power Plug +// https://es.aliexpress.com/item/-/32854589733.html?spm=a219c.12010608.0.0.6d084e68xX0y5N +// ----------------------------------------------------------------------------- + +#elif defined(NEO_COOLCAM_POWER_PLUG_WIFI) + + // Info + #define MANUFACTURER "NEO_COOLCAM" + #define DEVICE "POWER_PLUG_WIFI" + + // Buttons + #define BUTTON1_PIN 13 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY1_PIN 12 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 4 + #define LED1_PIN_INVERSE 1 + + +// ------------------------------------------------------------------------------ +// Estink Wifi Power Strip +// https://www.amazon.de/Steckdosenleiste-Ladeger%C3%A4t-Sprachsteuerung-SmartphonesTablets-Android/dp/B0796W5FZY +// Fornorm Wi-Fi USB Extension Socket (ZLD-34EU) +// https://www.aliexpress.com/item/Fornorm-WiFi-Extension-Socket-with-Surge-Protector-Smart-Power-Strip-3-Outlets-and-4-USB-Charging/32849743948.html +// ----------------------------------------------------------------------------- + +#elif defined(ESTINK_WIFI_POWER_STRIP) + + // Info + #define MANUFACTURER "ESTINK" + #define DEVICE "WIFI_POWER_STRIP" + + // Disable UART noise since this board uses GPIO3 + #define DEBUG_SERIAL_SUPPORT 0 + + // Buttons + #define BUTTON1_PIN 16 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 4 + + // Relays + #define RELAY1_PIN 14 // USB power + #define RELAY2_PIN 13 // power plug 1 + #define RELAY3_PIN 4 // power plug 2 + #define RELAY4_PIN 15 // power plug 3 + + #define RELAY1_TYPE RELAY_TYPE_NORMAL + #define RELAY2_TYPE RELAY_TYPE_NORMAL + #define RELAY3_TYPE RELAY_TYPE_NORMAL + #define RELAY4_TYPE RELAY_TYPE_NORMAL + + // LEDs + #define LED1_PIN 0 // power led + #define LED2_PIN 12 // power plug 1 + #define LED3_PIN 3 // power plug 2 + #define LED4_PIN 5 // power plug 3 + + #define LED1_PIN_INVERSE 1 + #define LED2_PIN_INVERSE 1 + #define LED3_PIN_INVERSE 1 + #define LED4_PIN_INVERSE 1 + + #define LED1_MODE LED_MODE_FINDME + #define LED2_MODE LED_MODE_FOLLOW + #define LED3_MODE LED_MODE_FOLLOW + #define LED4_MODE LED_MODE_FOLLOW + + #define LED2_RELAY 2 + #define LED3_RELAY 3 + #define LED4_RELAY 4 + +// ----------------------------------------------------------------------------- +// Generic Neopixels +// ----------------------------------------------------------------------------- + +#elif defined(GENERIC_FASTLED) + + // Info + #define MANUFACTURER "GENERIC" + #define DEVICE "FASTLED" + + // Buttons + #define BUTTON1_PIN 13 // 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 | BUTTON_SET_PULLUP + #define BUTTON1_RELAY 1 + + // Relays + #define RELAY_PROVIDER RELAY_PROVIDER_LIGHT + #define DUMMY_RELAY_COUNT 1 + + // LEDs + #define LED1_PIN 2 + #define LED1_PIN_INVERSE 1 + + #define LIGHT_PROVIDER LIGHT_PROVIDER_FASTLED + #define LIGHT_FASTLED_TYPE WS2812B + #define LIGHT_FASTLED_ORDER RGB + #define LIGHT_FASTLED_NUM 41 + #define LIGHT_FASTLED_DATA_PIN 5 + +// ----------------------------------------------------------------------------- +// TEST boards (do not use!!) +// ----------------------------------------------------------------------------- + +#elif defined(TRAVIS01) + + // Info + #define MANUFACTURER "TravisCI" + #define DEVICE "Virtual board 01" + + // Some buttons - pin 0 + #define BUTTON1_PIN 0 + #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_RELAY 1 + + // Some relays - pin 1 + #define RELAY1_PIN 1 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + + // Some LEDs - pin 2 + #define LED1_PIN 2 + #define LED1_PIN_INVERSE 1 + + // A bit of I2C - pins 3,4 + #define I2C_SDA_PIN 3 + #define I2C_SCL_PIN 4 + + // And, as they say in "From Dusk till Dawn": + // This is a sensor blow out! + // Alright, we got white sensor, black sensor, spanish sensor, yellow sensor. We got hot sensor, cold sensor. + // We got wet sensor. We got smelly sensor. We got hairy sensor, bloody sensor. We got snapping sensor. + // We got silk sensor, velvet sensor, naugahyde sensor. We even got horse sensor, dog sensor, chicken sensor. + // C'mon, you want sensor, come on in sensor lovers! + // If we don’t got it, you don't want it! + #define AM2320_SUPPORT 1 + #define BH1750_SUPPORT 1 + #define BMX280_SUPPORT 1 + #define SHT3X_I2C_SUPPORT 1 + #define EMON_ADC121_SUPPORT 1 + #define EMON_ADS1X15_SUPPORT 1 + #define SHT3X_I2C_SUPPORT 1 + #define SI7021_SUPPORT 1 + + + // A bit of lights - pin 5 + #define RELAY_PROVIDER RELAY_PROVIDER_LIGHT + #define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER + #define DUMMY_RELAY_COUNT 1 + #define LIGHT_CHANNELS 1 + #define LIGHT_CH1_PIN 5 + #define LIGHT_CH1_INVERSE 0 + + // A bit of HLW8012 - pins 6,7,8 + #ifndef HLW8012_SUPPORT + #define HLW8012_SUPPORT 1 + #endif + #define HLW8012_SEL_PIN 6 + #define HLW8012_CF1_PIN 7 + #define HLW8012_CF_PIN 8 + + // A bit of Dallas - pin 9 + #ifndef DALLAS_SUPPORT + #define DALLAS_SUPPORT 1 + #endif + #define DALLAS_PIN 9 + + // A bit of ECH1560 - pins 10,11, 12 + #ifndef ECH1560_SUPPORT + #define ECH1560_SUPPORT 1 + #endif + #define ECH1560_CLK_PIN 10 + #define ECH1560_MISO_PIN 11 + #define ECH1560_INVERTED 12 + +#elif defined(TRAVIS02) + + // Relay provider dual + #define MANUFACTURER "TravisCI" + #define DEVICE "Virtual board 02" + + // A bit of CSE7766 - pin 1 + #ifndef CSE7766_SUPPORT + #define CSE7766_SUPPORT 1 + #endif + #define CSE7766_PIN 1 + + // Relay type dual - pins 2,3 + #define RELAY_PROVIDER RELAY_PROVIDER_DUAL + #define RELAY1_PIN 2 + #define RELAY2_PIN 3 + #define RELAY1_TYPE RELAY_TYPE_NORMAL + #define RELAY2_TYPE RELAY_TYPE_NORMAL + + // IR - pin 4 + #define IR_SUPPORT 1 + #define IR_PIN 4 + #define IR_BUTTON_SET 1 + + // A bit of DHT - pin 5 + #ifndef DHT_SUPPORT + #define DHT_SUPPORT 1 + #endif + #define DHT_PIN 5 + + // A bit of TMP3X (analog) + #define TMP3X_SUPPORT 1 + + // A bit of EVENTS - pin 10 + #define EVENTS_SUPPORT 1 + #define EVENTS_PIN 6 + + // HC-RS04 + #define HCSR04_SUPPORT 1 + #define HCSR04_TRIGGER 7 + #define HCSR04_ECHO 8 + + // MHZ19 + #define MHZ19_SUPPORT 1 + #define MHZ19_RX_PIN 9 + #define MHZ19_TX_PIN 10 + + // PZEM004T + #define PZEM004T_SUPPORT 0 // not working? + #define PZEM004T_RX_PIN 11 + #define PZEM004T_TX_PIN 12 + + // V9261F + #define V9261F_SUPPORT 1 + #define V9261F_PIN 13 + + // GUVAS12SD + #define GUVAS12SD_SUPPORT 1 + #define GUVAS12SD_PIN 14 + +#elif defined(TRAVIS03) + + // Relay provider light/my92XX + #define MANUFACTURER "TravisCI" + #define DEVICE "Virtual board 03" + + // MY9231 Light - pins 1,2 + #define RELAY_PROVIDER RELAY_PROVIDER_LIGHT + #define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX + #define DUMMY_RELAY_COUNT 1 + #define LIGHT_CHANNELS 5 + #define MY92XX_MODEL MY92XX_MODEL_MY9231 + #define MY92XX_CHIPS 2 + #define MY92XX_DI_PIN 1 + #define MY92XX_DCKI_PIN 2 + #define MY92XX_COMMAND MY92XX_COMMAND_DEFAULT + #define MY92XX_MAPPING 4, 3, 5, 0, 1 + + // A bit of Analog EMON (analog) + #ifndef EMON_ANALOG_SUPPORT + #define EMON_ANALOG_SUPPORT 1 + #endif + +#endif + +// ----------------------------------------------------------------------------- +// Check definitions // ----------------------------------------------------------------------------- -#else - #error "UNSUPPORTED HARDWARE!" +#if not defined(MANUFACTURER) || not defined(DEVICE) + #error "UNSUPPORTED HARDWARE!!" #endif diff --git a/code/espurna/config/progmem.h b/code/espurna/config/progmem.h new file mode 100644 index 00000000..7f91f2da --- /dev/null +++ b/code/espurna/config/progmem.h @@ -0,0 +1,280 @@ +//-------------------------------------------------------------------------------- +// PROGMEM definitions +//-------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------- +// Reset reasons +//-------------------------------------------------------------------------------- + +PROGMEM const char custom_reset_hardware[] = "Hardware button"; +PROGMEM const char custom_reset_web[] = "Reboot from web interface"; +PROGMEM const char custom_reset_terminal[] = "Reboot from terminal"; +PROGMEM const char custom_reset_mqtt[] = "Reboot from MQTT"; +PROGMEM const char custom_reset_rpc[] = "Reboot from RPC"; +PROGMEM const char custom_reset_ota[] = "Reboot after successful OTA update"; +PROGMEM const char custom_reset_http[] = "Reboot from HTTP"; +PROGMEM const char custom_reset_nofuss[] = "Reboot after successful NoFUSS update"; +PROGMEM const char custom_reset_upgrade[] = "Reboot after successful web update"; +PROGMEM const char custom_reset_factory[] = "Factory reset"; +PROGMEM const char* const custom_reset_string[] = { + custom_reset_hardware, custom_reset_web, custom_reset_terminal, + custom_reset_mqtt, custom_reset_rpc, custom_reset_ota, + custom_reset_http, custom_reset_nofuss, custom_reset_upgrade, + custom_reset_factory +}; + +//-------------------------------------------------------------------------------- +// Capabilities +//-------------------------------------------------------------------------------- + +PROGMEM const char espurna_modules[] = + #if ALEXA_SUPPORT + "ALEXA " + #endif + #if BROKER_SUPPORT + "BROKER " + #endif + #if DEBUG_SERIAL_SUPPORT + "DEBUG_SERIAL " + #endif + #if DEBUG_TELNET_SUPPORT + "DEBUG_TELNET " + #endif + #if DEBUG_UDP_SUPPORT + "DEBUG_UDP " + #endif + #if DEBUG_WEB_SUPPORT + "DEBUG_WEB " + #endif + #if DOMOTICZ_SUPPORT + "DOMOTICZ " + #endif + #if HOMEASSISTANT_SUPPORT + "HOMEASSISTANT " + #endif + #if I2C_SUPPORT + "I2C " + #endif + #if INFLUXDB_SUPPORT + "INFLUXDB " + #endif + #if LLMNR_SUPPORT + "LLMNR " + #endif + #if MDNS_SERVER_SUPPORT + "MDNS_SERVER " + #endif + #if MDNS_CLIENT_SUPPORT + "MDNS_CLIENT " + #endif + #if MQTT_SUPPORT + "MQTT " + #endif + #if NETBIOS_SUPPORT + "NETBIOS " + #endif + #if NOFUSS_SUPPORT + "NOFUSS " + #endif + #if NTP_SUPPORT + "NTP " + #endif + #if RF_SUPPORT + "RF " + #endif + #if SCHEDULER_SUPPORT + "SCHEDULER " + #endif + #if SENSOR_SUPPORT + "SENSOR " + #endif + #if SPIFFS_SUPPORT + "SPIFFS " + #endif + #if SSDP_SUPPORT + "SSDP " + #endif + #if TELNET_SUPPORT + "TELNET " + #endif + #if TERMINAL_SUPPORT + "TERMINAL " + #endif + #if THINGSPEAK_SUPPORT + "THINGSPEAK " + #endif + #if UART_MQTT_SUPPORT + "UART_MQTT " + #endif + #if WEB_SUPPORT + "WEB " + #endif + ""; + +//-------------------------------------------------------------------------------- +// Sensors +//-------------------------------------------------------------------------------- + +#if SENSOR_SUPPORT + +PROGMEM const char espurna_sensors[] = + #if AM2320_SUPPORT + "AM2320_I2C " + #endif + #if ANALOG_SUPPORT + "ANALOG " + #endif + #if BH1750_SUPPORT + "BH1750 " + #endif + #if BMX280_SUPPORT + "BMX280 " + #endif + #if CSE7766_SUPPORT + "CSE7766 " + #endif + #if DALLAS_SUPPORT + "DALLAS " + #endif + #if DHT_SUPPORT + "DHTXX " + #endif + #if DIGITAL_SUPPORT + "DIGITAL " + #endif + #if ECH1560_SUPPORT + "ECH1560 " + #endif + #if EMON_ADC121_SUPPORT + "EMON_ADC121 " + #endif + #if EMON_ADS1X15_SUPPORT + "EMON_ADX1X15 " + #endif + #if EMON_ANALOG_SUPPORT + "EMON_ANALOG " + #endif + #if EVENTS_SUPPORT + "EVENTS " + #endif + #if GEIGER_SUPPORT + "GEIGER " + #endif + #if GUVAS12SD_SUPPORT + "GUVAS12SD " + #endif + #if HCSR04_SUPPORT + "HCSR04 " + #endif + #if HLW8012_SUPPORT + "HLW8012 " + #endif + #if MHZ19_SUPPORT + "MHZ19 " + #endif + #if PMSX003_SUPPORT + "PMSX003 " + #endif + #if PZEM004T_SUPPORT + "PZEM004T " + #endif + #if SENSEAIR_SUPPORT + "SENSEAIR " + #endif + #if SHT3X_I2C_SUPPORT + "SHT3X_I2C " + #endif + #if SI7021_SUPPORT + "SI7021 " + #endif + #if TMP3X_SUPPORT + "TMP3X " + #endif + #if V9261F_SUPPORT + "V9261F " + #endif + ""; + + +PROGMEM const unsigned char magnitude_decimals[] = { + 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 +}; + +PROGMEM const char magnitude_unknown_topic[] = "unknown"; +PROGMEM const char magnitude_temperature_topic[] = "temperature"; +PROGMEM const char magnitude_humidity_topic[] = "humidity"; +PROGMEM const char magnitude_pressure_topic[] = "pressure"; +PROGMEM const char magnitude_current_topic[] = "current"; +PROGMEM const char magnitude_voltage_topic[] = "voltage"; +PROGMEM const char magnitude_active_power_topic[] = "power"; +PROGMEM const char magnitude_apparent_power_topic[] = "apparent"; +PROGMEM const char magnitude_reactive_power_topic[] = "reactive"; +PROGMEM const char magnitude_power_factor_topic[] = "factor"; +PROGMEM const char magnitude_energy_topic[] = "energy"; +PROGMEM const char magnitude_energy_delta_topic[] = "energy_delta"; +PROGMEM const char magnitude_analog_topic[] = "analog"; +PROGMEM const char magnitude_digital_topic[] = "digital"; +PROGMEM const char magnitude_events_topic[] = "events"; +PROGMEM const char magnitude_pm1dot0_topic[] = "pm1dot0"; +PROGMEM const char magnitude_pm2dot5_topic[] = "pm2dot5"; +PROGMEM const char magnitude_pm10_topic[] = "pm10"; +PROGMEM const char magnitude_co2_topic[] = "co2"; +PROGMEM const char magnitude_lux_topic[] = "lux"; +PROGMEM const char magnitude_uv_topic[] = "uv"; +PROGMEM const char magnitude_distance_topic[] = "distance"; +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_sv_topic[] = "ldr_uSvh"; // local dose rate [µSievert per hour] + +PROGMEM const char* const magnitude_topics[] = { + magnitude_unknown_topic, magnitude_temperature_topic, magnitude_humidity_topic, + magnitude_pressure_topic, magnitude_current_topic, magnitude_voltage_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_analog_topic, magnitude_digital_topic, magnitude_events_topic, + magnitude_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic, + magnitude_co2_topic, magnitude_lux_topic, magnitude_uv_topic, + magnitude_distance_topic, magnitude_hcho_topic, + magnitude_geiger_cpm_topic, magnitude_geiger_sv_topic // Geiger Counter topics +}; + +PROGMEM const char magnitude_empty[] = ""; +PROGMEM const char magnitude_celsius[] = "°C"; +PROGMEM const char magnitude_fahrenheit[] = "°F"; +PROGMEM const char magnitude_percentage[] = "%"; +PROGMEM const char magnitude_hectopascals[] = "hPa"; +PROGMEM const char magnitude_amperes[] = "A"; +PROGMEM const char magnitude_volts[] = "V"; +PROGMEM const char magnitude_watts[] = "W"; +PROGMEM const char magnitude_kw[] = "kW"; +PROGMEM const char magnitude_joules[] = "J"; +PROGMEM const char magnitude_kwh[] = "kWh"; +PROGMEM const char magnitude_ugm3[] = "µg/m³"; +PROGMEM const char magnitude_ppm[] = "ppm"; +PROGMEM const char magnitude_lux[] = "lux"; +PROGMEM const char magnitude_uv[] = "uv"; +PROGMEM const char magnitude_distance[] = "m"; +PROGMEM const char magnitude_mgm3[] = "mg/m³"; +PROGMEM const char magnitude_geiger_cpm[] = "cpm"; // Counts per Minute: Unit of local dose rate (Geiger counting) +PROGMEM const char magnitude_geiger_sv[] = "µSv/h"; // µSievert per hour: 2nd unit of local dose rate (Geiger counting) + + +PROGMEM const char* const magnitude_units[] = { + magnitude_empty, magnitude_celsius, magnitude_percentage, + magnitude_hectopascals, magnitude_amperes, magnitude_volts, + magnitude_watts, magnitude_watts, magnitude_watts, + magnitude_percentage, magnitude_joules, magnitude_joules, + magnitude_empty, magnitude_empty, magnitude_empty, + magnitude_ugm3, magnitude_ugm3, magnitude_ugm3, + magnitude_ppm, magnitude_lux, magnitude_uv, + magnitude_distance, magnitude_mgm3, + magnitude_geiger_cpm, magnitude_geiger_sv // Geiger counter units +}; + +#endif diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index 2239c523..6db0a23b 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -7,6 +7,12 @@ extern "C" { #include "user_interface.h" } +// ----------------------------------------------------------------------------- +// EEPROM_ROTATE +// ----------------------------------------------------------------------------- +#include +EEPROM_Rotate EEPROMr; + // ----------------------------------------------------------------------------- // WebServer // ----------------------------------------------------------------------------- @@ -27,34 +33,72 @@ typedef std::function ws_on_send_callback_f; void wsOnSendRegister(ws_on_send_callback_f callback); void wsSend(ws_on_send_callback_f sender); -typedef std::function ws_on_action_callback_f; +typedef std::function ws_on_action_callback_f; void wsOnActionRegister(ws_on_action_callback_f callback); typedef std::function ws_on_after_parse_callback_f; void wsOnAfterParseRegister(ws_on_after_parse_callback_f callback); +typedef std::function ws_on_receive_callback_f; +void wsOnReceiveRegister(ws_on_receive_callback_f callback); + +// ----------------------------------------------------------------------------- +// WIFI +// ----------------------------------------------------------------------------- +#include "JustWifi.h" +typedef std::function wifi_callback_f; +void wifiRegister(wifi_callback_f callback); + // ----------------------------------------------------------------------------- // MQTT // ----------------------------------------------------------------------------- typedef std::function mqtt_callback_f; void mqttRegister(mqtt_callback_f callback); -String mqttSubtopic(char * topic); +String mqttMagnitude(char * topic); + +// ----------------------------------------------------------------------------- +// Broker +// ----------------------------------------------------------------------------- +void brokerRegister(void (*)(const char *, unsigned char, const char *)); // ----------------------------------------------------------------------------- // Settings // ----------------------------------------------------------------------------- +#include template bool setSetting(const String& key, T value); template bool setSetting(const String& key, unsigned int index, T value); template String getSetting(const String& key, T defaultValue); template String getSetting(const String& key, unsigned int index, T defaultValue); -bool settingsRestore(JsonObject& data); +void settingsGetJson(JsonObject& data); +bool settingsRestoreJson(JsonObject& data); +void settingsRegisterCommand(const String& name, void (*call)(Embedis*)); +void settingsInject(void *data, size_t len); +Stream & settingsSerial(); // ----------------------------------------------------------------------------- // I2C // ----------------------------------------------------------------------------- -unsigned char i2cFindAndLock(size_t size, unsigned char * addresses); +void i2cScan(); +void i2cClearBus(); bool i2cGetLock(unsigned char address); bool i2cReleaseLock(unsigned char address); +unsigned char i2cFindAndLock(size_t size, unsigned char * addresses); + +void i2c_wakeup(uint8_t address); +uint8_t i2c_write_buffer(uint8_t address, uint8_t * buffer, size_t len); +uint8_t i2c_write_uint8(uint8_t address, uint8_t value); +uint8_t i2c_write_uint8(uint8_t address, uint8_t reg, uint8_t value); +uint8_t i2c_write_uint8(uint8_t address, uint8_t reg, uint8_t value1, uint8_t value2); +uint8_t i2c_write_uint16(uint8_t address, uint16_t value); +uint8_t i2c_write_uint16(uint8_t address, uint8_t reg, uint16_t value); +uint8_t i2c_read_uint8(uint8_t address); +uint8_t i2c_read_uint8(uint8_t address, uint8_t reg); +uint16_t i2c_read_uint16(uint8_t address); +uint16_t i2c_read_uint16(uint8_t address, uint8_t reg); +uint16_t i2c_read_uint16_le(uint8_t address, uint8_t reg); +int16_t i2c_read_int16(uint8_t address, uint8_t reg); +int16_t i2c_read_int16_le(uint8_t address, uint8_t reg); +void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len); // ----------------------------------------------------------------------------- // GPIO @@ -75,13 +119,11 @@ void debugSend_P(PGM_P format, ...); template void domoticzSend(const char * key, T value); template void domoticzSend(const char * key, T nvalue, const char * svalue); -// ----------------------------------------------------------------------------- -// InfluxDB -// ----------------------------------------------------------------------------- -template bool idbSend(const char * topic, T payload); -template bool idbSend(const char * topic, unsigned char id, T payload); - // ----------------------------------------------------------------------------- // Utils // ----------------------------------------------------------------------------- char * ltrim(char * s); +void nice_delay(unsigned long ms); + +#define ARRAYINIT(type, name, ...) \ + type name[] = {__VA_ARGS__}; diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h index 957676cc..afc86988 100644 --- a/code/espurna/config/sensors.h +++ b/code/espurna/config/sensors.h @@ -7,6 +7,7 @@ #define SENSOR_READ_INTERVAL 6 // Read data from sensors every 6 seconds #define SENSOR_READ_MIN_INTERVAL 6 // Minimum read interval #define SENSOR_READ_MAX_INTERVAL 3600 // Maximum read interval +#define SENSOR_INIT_INTERVAL 10000 // Try to re-init non-ready sensors every 10s #define SENSOR_REPORT_EVERY 10 // Report every this many readings #define SENSOR_REPORT_MIN_EVERY 1 // Minimum every value @@ -15,8 +16,8 @@ #define SENSOR_USE_INDEX 0 // Use the index in topic (i.e. temperature/0) // even if just one sensor (0 for backwards compatibility) -#ifndef SENSOR_TEMPERATURE_UNITS -#define SENSOR_TEMPERATURE_UNITS TMP_CELSIUS // Temperature units (TMP_CELSIUS | TMP_FAHRENHEIT) +#ifndef SENSOR_POWER_CHECK_STATUS +#define SENSOR_POWER_CHECK_STATUS 1 // If set to 1 the reported power/current/energy will be 0 if the relay[0] is OFF #endif #ifndef SENSOR_TEMPERATURE_CORRECTION @@ -27,69 +28,48 @@ #define TEMPERATURE_MIN_CHANGE 0.0 // Minimum temperature change to report #endif +#ifndef SENSOR_HUMIDITY_CORRECTION +#define SENSOR_HUMIDITY_CORRECTION 0.0 // Offset correction +#endif + #ifndef HUMIDITY_MIN_CHANGE #define HUMIDITY_MIN_CHANGE 0 // Minimum humidity change to report #endif -#define HUMIDITY_NORMAL 0 -#define HUMIDITY_COMFORTABLE 1 -#define HUMIDITY_DRY 2 -#define HUMIDITY_WET 3 +#define SENSOR_PUBLISH_ADDRESSES 0 // Publish sensor addresses +#define SENSOR_ADDRESS_TOPIC "address" // Topic to publish sensor addresses -//-------------------------------------------------------------------------------- -// Sensor ID -// These should remain over time, do not modify them, only add new ones at the end -//-------------------------------------------------------------------------------- -#define SENSOR_DHTXX_ID 0x01 -#define SENSOR_DALLAS_ID 0x02 -#define SENSOR_EMON_ANALOG_ID 0x03 -#define SENSOR_EMON_ADC121_ID 0x04 -#define SENSOR_EMON_ADS1X15_ID 0x05 -#define SENSOR_HLW8012_ID 0x06 -#define SENSOR_V9261F_ID 0x07 -#define SENSOR_ECH1560_ID 0x08 -#define SENSOR_ANALOG_ID 0x09 -#define SENSOR_DIGITAL_ID 0x10 -#define SENSOR_EVENTS_ID 0x11 -#define SENSOR_PMSX003_ID 0x12 -#define SENSOR_BMX280_ID 0x13 -#define SENSOR_MHZ19_ID 0x14 -#define SENSOR_SI7021_ID 0x15 -#define SENSOR_SHT3X_I2C_ID 0x16 -#define SENSOR_BH1750_ID 0x17 +#ifndef SENSOR_TEMPERATURE_UNITS +#define SENSOR_TEMPERATURE_UNITS TMP_CELSIUS // Temperature units (TMP_CELSIUS | TMP_FAHRENHEIT) +#endif -//-------------------------------------------------------------------------------- -// Magnitudes -//-------------------------------------------------------------------------------- +#ifndef SENSOR_ENERGY_UNITS +#define SENSOR_ENERGY_UNITS ENERGY_JOULES // Energy units (ENERGY_JOULES | ENERGY_KWH) +#endif + +#ifndef SENSOR_POWER_UNITS +#define SENSOR_POWER_UNITS POWER_WATTS // Power units (POWER_WATTS | POWER_KILOWATTS) +#endif -#define MAGNITUDE_NONE 0 -#define MAGNITUDE_TEMPERATURE 1 -#define MAGNITUDE_HUMIDITY 2 -#define MAGNITUDE_PRESSURE 3 -#define MAGNITUDE_CURRENT 4 -#define MAGNITUDE_VOLTAGE 5 -#define MAGNITUDE_POWER_ACTIVE 6 -#define MAGNITUDE_POWER_APPARENT 7 -#define MAGNITUDE_POWER_REACTIVE 8 -#define MAGNITUDE_POWER_FACTOR 9 -#define MAGNITUDE_ENERGY 10 -#define MAGNITUDE_ENERGY_DELTA 11 -#define MAGNITUDE_ANALOG 12 -#define MAGNITUDE_DIGITAL 13 -#define MAGNITUDE_EVENTS 14 -#define MAGNITUDE_PM1dot0 15 -#define MAGNITUDE_PM2dot5 16 -#define MAGNITUDE_PM10 17 -#define MAGNITUDE_CO2 18 -#define MAGNITUDE_LUX 19 - -#define MAGNITUDE_MAX 20 // ============================================================================= // Specific data for each sensor // ============================================================================= +//------------------------------------------------------------------------------ +// AM2320 Humidity & Temperature sensor over I2C +// Enable support by passing AM2320_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef AM2320_SUPPORT +#define AM2320_SUPPORT 0 +#endif + +#ifndef AM2320_ADDRESS +#define AM2320_ADDRESS 0x00 // 0x00 means auto +#endif + //------------------------------------------------------------------------------ // Analog sensor // Enable support by passing ANALOG_SUPPORT=1 build flag @@ -99,11 +79,6 @@ #define ANALOG_SUPPORT 0 #endif -#if ANALOG_SUPPORT -#undef ADC_VCC_ENABLED -#define ADC_VCC_ENABLED 0 -#endif - //------------------------------------------------------------------------------ // BH1750 // Enable support by passing BH1750_SUPPORT=1 build flag @@ -120,11 +95,6 @@ #define BH1750_MODE BH1750_CONTINUOUS_HIGH_RES_MODE -#if BH1750_SUPPORT -#undef I2C_SUPPORT -#define I2C_SUPPORT 1 -#endif - //------------------------------------------------------------------------------ // BME280/BMP280 // Enable support by passing BMX280_SUPPORT=1 build flag @@ -138,16 +108,15 @@ #define BMX280_ADDRESS 0x00 // 0x00 means auto #endif -#define BMX280_MODE 1 // 1 for forced mode, 3 for normal mode +#define BMX280_MODE 1 // 0 for sleep mode, 1 or 2 for forced mode, 3 for normal mode +#define BMX280_STANDBY 0 // 0 for 0.5ms, 1 for 62.5ms, 2 for 125ms + // 3 for 250ms, 4 for 500ms, 5 for 1000ms + // 6 for 10ms, 7 for 20ms +#define BMX280_FILTER 0 // 0 for OFF, 1 for 2 values, 2 for 4 values, 3 for 8 values and 4 for 16 values #define BMX280_TEMPERATURE 1 // Oversampling for temperature (set to 0 to disable magnitude) #define BMX280_HUMIDITY 1 // Oversampling for humidity (set to 0 to disable magnitude, only for BME280) #define BMX280_PRESSURE 1 // Oversampling for pressure (set to 0 to disable magnitude) -#if BMX280_SUPPORT -#undef I2C_SUPPORT -#define I2C_SUPPORT 1 -#endif - //------------------------------------------------------------------------------ // Dallas OneWire temperature sensors // Enable support by passing DALLAS_SUPPORT=1 build flag @@ -161,8 +130,8 @@ #define DALLAS_PIN 14 #endif -#define DALLAS_RESOLUTION 9 // Not used atm -#define DALLAS_READ_INTERVAL 2000 // Force sensor read & cache every 2 seconds +#define DALLAS_RESOLUTION 9 // Not used atm +#define DALLAS_READ_INTERVAL 2000 // Force sensor read & cache every 2 seconds //------------------------------------------------------------------------------ // DHTXX temperature/humidity sensor @@ -181,6 +150,30 @@ #define DHT_TYPE DHT_CHIP_DHT22 #endif +//------------------------------------------------------------------------------ +// CSE7766 based power sensor +// Enable support by passing CSE7766_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef CSE7766_SUPPORT +#define CSE7766_SUPPORT 0 +#endif + +#ifndef CSE7766_PIN +#define CSE7766_PIN 1 // TX pin from the CSE7766 +#endif + +#ifndef CSE7766_PIN_INVERSE +#define CSE7766_PIN_INVERSE 0 // Signal is inverted +#endif + +#define CSE7766_SYNC_INTERVAL 300 // Safe time between transmissions (ms) +#define CSE7766_BAUDRATE 4800 // UART baudrate + +#define CSE7766_V1R 1.0 // 1mR current resistor +#define CSE7766_V2R 1.0 // 1M voltage resistor + + //------------------------------------------------------------------------------ // Digital sensor // Enable support by passing DIGITAL_SUPPORT=1 build flag @@ -248,11 +241,6 @@ #define EMON_ADC121_I2C_ADDRESS 0x00 // 0x00 means auto -#if EMON_ADC121_SUPPORT -#undef I2C_SUPPORT -#define I2C_SUPPORT 1 -#endif - //------------------------------------------------------------------------------ // Energy Monitor based on ADS1X15 // Enable support by passing EMON_ADS1X15_SUPPORT=1 build flag @@ -265,12 +253,7 @@ #define EMON_ADS1X15_I2C_ADDRESS 0x00 // 0x00 means auto #define EMON_ADS1X15_TYPE ADS1X15_CHIP_ADS1115 #define EMON_ADS1X15_GAIN ADS1X15_REG_CONFIG_PGA_4_096V -#define EMON_ADS1X15_MASK 0x0F // A0=1 A1=2 A2=4 A4=8 - -#if EMON_ADS1X15_SUPPORT -#undef I2C_SUPPORT -#define I2C_SUPPORT 1 -#endif +#define EMON_ADS1X15_MASK 0x0F // A0=1 A1=2 A2=4 A3=8 //------------------------------------------------------------------------------ // Energy Monitor based on interval analog GPIO @@ -281,11 +264,6 @@ #define EMON_ANALOG_SUPPORT 0 // Do not build support by default #endif -#if EMON_ANALOG_SUPPORT -#undef ADC_VCC_ENABLED -#define ADC_VCC_ENABLED 0 -#endif - //------------------------------------------------------------------------------ // Counter sensor // Enable support by passing EVENTS_SUPPORT=1 build flag @@ -307,7 +285,66 @@ #define EVENTS_INTERRUPT_MODE RISING // RISING, FALLING, BOTH #endif -#define EVENTS_DEBOUNCE 50 // Do not register events within less than 10 millis +#define EVENTS_DEBOUNCE 50 // Do not register events within less than 50 millis + +//------------------------------------------------------------------------------ +// Geiger sensor +// Enable support by passing GEIGER_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef GEIGER_SUPPORT +#define GEIGER_SUPPORT 0 // Do not build with geiger support by default +#endif + +#ifndef GEIGER_PIN +#define GEIGER_PIN D1 // GPIO to monitor "D1" => "GPIO5" +#endif + +#ifndef GEIGER_PIN_MODE +#define GEIGER_PIN_MODE INPUT // INPUT, INPUT_PULLUP +#endif + +#ifndef GEIGER_INTERRUPT_MODE +#define GEIGER_INTERRUPT_MODE RISING // RISING, FALLING, BOTH +#endif + +#define GEIGER_DEBOUNCE 25 // Do not register events within less than 25 millis. + // Value derived here: Debounce time 25ms, because https://github.com/Trickx/espurna/wiki/Geiger-counter + +#define GEIGER_CPM2SIEVERT 240 // CPM to µSievert per hour conversion factor + // Typically the literature uses the invers, but I find an integer type more convienient. +#define GEIGER_REPORT_SIEVERTS 1 // Enabler for local dose rate reports in µSv/h +#define GEIGER_REPORT_CPM 1 // Enabler for local dose rate reports in counts per minute + +//------------------------------------------------------------------------------ +// GUVAS12SD UV Sensor (analog) +// Enable support by passing GUVAS12SD_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef GUVAS12SD_SUPPORT +#define GUVAS12SD_SUPPORT 0 +#endif + +#ifndef GUVAS12SD_PIN +#define GUVAS12SD_PIN 14 +#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 @@ -357,11 +394,33 @@ #define MHZ19_SUPPORT 0 #endif +#ifndef MHZ19_RX_PIN #define MHZ19_RX_PIN 13 +#endif + +#ifndef MHZ19_TX_PIN #define MHZ19_TX_PIN 15 +#endif //------------------------------------------------------------------------------ -// Particle Monitor based on Plantower PMSX003 +// SenseAir CO2 sensor +// Enable support by passing SENSEAIR_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef SENSEAIR_SUPPORT +#define SENSEAIR_SUPPORT 0 +#endif + +#ifndef SENSEAIR_RX_PIN +#define SENSEAIR_RX_PIN 0 +#endif + +#ifndef SENSEAIR_TX_PIN +#define SENSEAIR_TX_PIN 2 +#endif + +//------------------------------------------------------------------------------ +// Particle Monitor based on Plantower PMS // Enable support by passing PMSX003_SUPPORT=1 build flag //------------------------------------------------------------------------------ @@ -369,8 +428,49 @@ #define PMSX003_SUPPORT 0 #endif +#ifndef PMS_TYPE +#define PMS_TYPE PMS_TYPE_X003 +#endif + +// You can enable smart sleep (read 6-times then sleep on 24-reading-cycles) to extend PMS sensor's life. +// Otherwise the default lifetime of PMS sensor is about 8000-hours/1-years. +// The PMS's fan will stop working on sleeping cycle, and will wake up on reading cycle. +#ifndef PMS_SMART_SLEEP +#define PMS_SMART_SLEEP 0 +#endif + +#ifndef PMS_RX_PIN #define PMS_RX_PIN 13 +#endif + +#ifndef PMS_TX_PIN #define PMS_TX_PIN 15 +#endif + +//------------------------------------------------------------------------------ +// PZEM004T based power monitor +// Enable support by passing PZEM004T_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef PZEM004T_SUPPORT +#define PZEM004T_SUPPORT 0 +#endif + +#ifndef PZEM004T_USE_SOFT +#define PZEM004T_USE_SOFT 0 // Software serial is not working atm, use hardware serial +#endif + +#ifndef PZEM004T_RX_PIN +#define PZEM004T_RX_PIN 13 // Software serial RX GPIO (if PZEM004T_USE_SOFT == 1) +#endif + +#ifndef PZEM004T_TX_PIN +#define PZEM004T_TX_PIN 15 // Software serial TX GPIO (if PZEM004T_USE_SOFT == 1) +#endif + +#ifndef PZEM004T_HW_PORT +#define PZEM004T_HW_PORT Serial1 // Hardware serial port (if PZEM004T_USE_SOFT == 0) +#endif //------------------------------------------------------------------------------ // SHT3X I2C (Wemos) temperature & humidity sensor @@ -385,11 +485,6 @@ #define SHT3X_I2C_ADDRESS 0x00 // 0x00 means auto #endif -#if SHT3X_I2C_SUPPORT -#undef I2C_SUPPORT -#define I2C_SUPPORT 1 -#endif - //------------------------------------------------------------------------------ // SI7021 temperature & humidity sensor // Enable support by passing SI7021_SUPPORT=1 build flag @@ -403,9 +498,17 @@ #define SI7021_ADDRESS 0x00 // 0x00 means auto #endif -#if SI7021_SUPPORT -#undef I2C_SUPPORT -#define I2C_SUPPORT 1 +//------------------------------------------------------------------------------ +// TMP3X analog temperature sensor +// Enable support by passing TMP3X_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef TMP3X_SUPPORT +#define TMP3X_SUPPORT 0 +#endif + +#ifndef TMP3X_TYPE +#define TMP3X_TYPE TMP3X_TMP35 #endif //------------------------------------------------------------------------------ @@ -435,18 +538,46 @@ #define V9261F_RPOWER_FACTOR V9261F_CURRENT_FACTOR // ============================================================================= -// Sensor helpers configuration +// Sensor helpers configuration - can't move to dependencies.h // ============================================================================= -#if ANALOG_SUPPORT || BH1750_SUPPORT || BMX280_SUPPORT || DALLAS_SUPPORT \ - || DHT_SUPPORT || DIGITAL_SUPPORT || ECH1560_SUPPORT \ - || EMON_ADC121_SUPPORT || EMON_ADS1X15_SUPPORT \ - || EMON_ANALOG_SUPPORT || EVENTS_SUPPORT || HLW8012_SUPPORT \ - || MHZ19_SUPPORT || PMSX003_SUPPORT || SHT3X_I2C_SUPPORT \ - || SI7021_SUPPORT || V9261F_SUPPORT +#ifndef SENSOR_SUPPORT +#define SENSOR_SUPPORT ( \ + AM2320_SUPPORT || \ + ANALOG_SUPPORT || \ + BH1750_SUPPORT || \ + BMX280_SUPPORT || \ + CSE7766_SUPPORT || \ + DALLAS_SUPPORT || \ + DHT_SUPPORT || \ + DIGITAL_SUPPORT || \ + ECH1560_SUPPORT || \ + EMON_ADC121_SUPPORT || \ + EMON_ADS1X15_SUPPORT || \ + EMON_ANALOG_SUPPORT || \ + EVENTS_SUPPORT || \ + GEIGER_SUPPORT || \ + GUVAS12SD_SUPPORT || \ + HCSR04_SUPPORT || \ + HLW8012_SUPPORT || \ + MHZ19_SUPPORT || \ + SENSEAIR_SUPPORT || \ + PMSX003_SUPPORT || \ + PZEM004T_SUPPORT || \ + SHT3X_I2C_SUPPORT || \ + SI7021_SUPPORT || \ + TMP3X_SUPPORT || \ + V9261F_SUPPORT \ +) +#endif -#define SENSOR_SUPPORT 1 +// ----------------------------------------------------------------------------- +// ADC +// ----------------------------------------------------------------------------- +// Default ADC mode is to monitor internal power supply +#ifndef ADC_MODE_VALUE +#define ADC_MODE_VALUE ADC_VCC #endif // ----------------------------------------------------------------------------- @@ -469,21 +600,8 @@ #define I2C_CLOCK_STRETCH_TIME 200 // BRZO clock stretch time #define I2C_SCL_FREQUENCY 1000 // BRZO SCL frequency -#define I2C_CLEAR_BUS 0 // Clear I2C bus at boot - -//-------------------------------------------------------------------------------- -// Internal power monitor -// Enable support by passing ADC_VCC_ENABLED=1 build flag -// Do not enable this if using the analog GPIO for any other thing -//-------------------------------------------------------------------------------- - -#ifndef ADC_VCC_ENABLED -#define ADC_VCC_ENABLED 1 -#endif - -#if ADC_VCC_ENABLED - ADC_MODE(ADC_VCC); -#endif +#define I2C_CLEAR_BUS 0 // Clear I2C bus on boot +#define I2C_PERFORM_SCAN 1 // Perform a bus scan on boot //-------------------------------------------------------------------------------- // Class loading @@ -491,71 +609,16 @@ #if SENSOR_SUPPORT -PROGMEM const unsigned char magnitude_decimals[] = { - 0, - 1, 0, 2, - 3, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - 0, 0, 0, - 0, 0 -}; - -PROGMEM const char magnitude_unknown_topic[] = "unknown"; -PROGMEM const char magnitude_temperature_topic[] = "temperature"; -PROGMEM const char magnitude_humidity_topic[] = "humidity"; -PROGMEM const char magnitude_pressure_topic[] = "pressure"; -PROGMEM const char magnitude_current_topic[] = "current"; -PROGMEM const char magnitude_voltage_topic[] = "voltage"; -PROGMEM const char magnitude_active_power_topic[] = "power"; -PROGMEM const char magnitude_apparent_power_topic[] = "apparent"; -PROGMEM const char magnitude_reactive_power_topic[] = "reactive"; -PROGMEM const char magnitude_power_factor_topic[] = "factor"; -PROGMEM const char magnitude_energy_topic[] = "energy"; -PROGMEM const char magnitude_energy_delta_topic[] = "energy_delta"; -PROGMEM const char magnitude_pm1dot0_topic[] = "pm1dot0"; -PROGMEM const char magnitude_pm2dot5_topic[] = "pm2dot5"; -PROGMEM const char magnitude_pm10_topic[] = "pm10"; -PROGMEM const char magnitude_analog_topic[] = "analog"; -PROGMEM const char magnitude_digital_topic[] = "digital"; -PROGMEM const char magnitude_events_topic[] = "events"; -PROGMEM const char magnitude_co2_topic[] = "co2"; -PROGMEM const char magnitude_lux_topic[] = "lux"; - -PROGMEM const char* const magnitude_topics[] = { - magnitude_unknown_topic, magnitude_temperature_topic, magnitude_humidity_topic, - magnitude_pressure_topic, magnitude_current_topic, magnitude_voltage_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_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic, - magnitude_analog_topic, magnitude_digital_topic, magnitude_events_topic, - magnitude_co2_topic, magnitude_lux_topic -}; - -PROGMEM const char magnitude_empty[] = ""; -PROGMEM const char magnitude_celsius[] = "C"; -PROGMEM const char magnitude_fahrenheit[] = "F"; -PROGMEM const char magnitude_percentage[] = "%"; -PROGMEM const char magnitude_hectopascals[] = "hPa"; -PROGMEM const char magnitude_amperes[] = "A"; -PROGMEM const char magnitude_volts[] = "V"; -PROGMEM const char magnitude_watts[] = "W"; -PROGMEM const char magnitude_joules[] = "J"; -PROGMEM const char magnitude_ugm3[] = "µg/m3"; -PROGMEM const char magnitude_ppm[] = "ppm"; -PROGMEM const char magnitude_lux[] = "lux"; - -PROGMEM const char* const magnitude_units[] = { - magnitude_empty, magnitude_celsius, magnitude_percentage, - magnitude_hectopascals, magnitude_amperes, magnitude_volts, - magnitude_watts, magnitude_watts, magnitude_watts, - magnitude_percentage, magnitude_joules, magnitude_joules, - magnitude_ugm3, magnitude_ugm3, magnitude_ugm3, - magnitude_empty, magnitude_empty, magnitude_empty, - magnitude_ppm, magnitude_lux -}; +#if SENSOR_DEBUG + #include "../config/debug.h" +#endif #include "../sensors/BaseSensor.h" +#if AM2320_SUPPORT + #include "../sensors/AM2320Sensor.h" +#endif + #if ANALOG_SUPPORT #include "../sensors/AnalogSensor.h" #endif @@ -565,10 +628,14 @@ PROGMEM const char* const magnitude_units[] = { #endif #if BMX280_SUPPORT - #include #include "../sensors/BMX280Sensor.h" #endif +#if CSE7766_SUPPORT + #include + #include "../sensors/CSE7766Sensor.h" +#endif + #if DALLAS_SUPPORT #include #include "../sensors/DallasSensor.h" @@ -602,6 +669,18 @@ PROGMEM const char* const magnitude_units[] = { #include "../sensors/EventSensor.h" #endif +#if GEIGER_SUPPORT + #include "../sensors/GeigerSensor.h" // The main file for geiger counting module +#endif + +#if GUVAS12SD_SUPPORT + #include "../sensors/GUVAS12SDSensor.h" +#endif + +#if HCSR04_SUPPORT + #include "../sensors/HCSR04Sensor.h" +#endif + #if HLW8012_SUPPORT #include #include "../sensors/HLW8012Sensor.h" @@ -612,12 +691,21 @@ PROGMEM const char* const magnitude_units[] = { #include "../sensors/MHZ19Sensor.h" #endif +#if SENSEAIR_SUPPORT + #include + #include "../sensors/SenseAirSensor.h" +#endif + #if PMSX003_SUPPORT #include - #include #include "../sensors/PMSX003Sensor.h" #endif +#if PZEM004T_SUPPORT + #include + #include "../sensors/PZEM004TSensor.h" +#endif + #if SI7021_SUPPORT #include "../sensors/SI7021Sensor.h" #endif @@ -626,6 +714,10 @@ PROGMEM const char* const magnitude_units[] = { #include "../sensors/SHT3XI2CSensor.h" #endif +#if TMP3X_SUPPORT + #include "../sensors/TMP3XSensor.h" +#endif + #if V9261F_SUPPORT #include #include "../sensors/V9261FSensor.h" diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h new file mode 100644 index 00000000..552cbe51 --- /dev/null +++ b/code/espurna/config/types.h @@ -0,0 +1,303 @@ +//------------------------------------------------------------------------------ +// Type definitions +// Do not touch this definitions +//------------------------------------------------------------------------------ + +// ----------------------------------------------------------------------------- +// WIFI +// ----------------------------------------------------------------------------- + +#define WIFI_STATE_AP 1 +#define WIFI_STATE_STA 2 +#define WIFI_STATE_AP_STA 3 +#define WIFI_STATE_WPS 4 +#define WIFI_STATE_SMARTCONFIG 8 + +#define WIFI_AP_ALLWAYS 1 +#define WIFI_AP_FALLBACK 2 + +//------------------------------------------------------------------------------ +// BUTTONS +//------------------------------------------------------------------------------ + +#define BUTTON_EVENT_NONE 0 +#define BUTTON_EVENT_PRESSED 1 +#define BUTTON_EVENT_RELEASED 2 +#define BUTTON_EVENT_CLICK 2 +#define BUTTON_EVENT_DBLCLICK 3 +#define BUTTON_EVENT_LNGCLICK 4 +#define BUTTON_EVENT_LNGLNGCLICK 5 +#define BUTTON_EVENT_TRIPLECLICK 6 + +#define BUTTON_MODE_NONE 0 +#define BUTTON_MODE_TOGGLE 1 +#define BUTTON_MODE_ON 2 +#define BUTTON_MODE_OFF 3 +#define BUTTON_MODE_AP 4 +#define BUTTON_MODE_RESET 5 +#define BUTTON_MODE_PULSE 6 +#define BUTTON_MODE_FACTORY 7 +#define BUTTON_MODE_WPS 8 +#define BUTTON_MODE_SMART_CONFIG 9 + +// Needed for ESP8285 boards under Windows using PlatformIO (?) +#ifndef BUTTON_PUSHBUTTON +#define BUTTON_PUSHBUTTON 0 +#define BUTTON_SWITCH 1 +#define BUTTON_DEFAULT_HIGH 2 +#define BUTTON_SET_PULLUP 4 +#endif + +//------------------------------------------------------------------------------ +// RELAY +//------------------------------------------------------------------------------ + +#define RELAY_BOOT_OFF 0 +#define RELAY_BOOT_ON 1 +#define RELAY_BOOT_SAME 2 +#define RELAY_BOOT_TOGGLE 3 + +#define RELAY_TYPE_NORMAL 0 +#define RELAY_TYPE_INVERSE 1 +#define RELAY_TYPE_LATCHED 2 +#define RELAY_TYPE_LATCHED_INVERSE 3 + +#define RELAY_SYNC_ANY 0 +#define RELAY_SYNC_NONE_OR_ONE 1 +#define RELAY_SYNC_ONE 2 +#define RELAY_SYNC_SAME 3 + +#define RELAY_PULSE_NONE 0 +#define RELAY_PULSE_OFF 1 +#define RELAY_PULSE_ON 2 + +#define RELAY_PROVIDER_RELAY 0 +#define RELAY_PROVIDER_DUAL 1 +#define RELAY_PROVIDER_LIGHT 2 +#define RELAY_PROVIDER_RFBRIDGE 3 +#define RELAY_PROVIDER_STM 4 + +//------------------------------------------------------------------------------ +// UDP SYSLOG +//------------------------------------------------------------------------------ + +// 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 */ + +// 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 */ + +//------------------------------------------------------------------------------ +// MQTT +//------------------------------------------------------------------------------ + +// Internal MQTT events +#define MQTT_CONNECT_EVENT 0 +#define MQTT_DISCONNECT_EVENT 1 +#define MQTT_MESSAGE_EVENT 2 + +//------------------------------------------------------------------------------ +// LED +//------------------------------------------------------------------------------ + +#define LED_MODE_MQTT 0 // LED will be managed from MQTT (OFF by default) +#define LED_MODE_WIFI 1 // LED will blink according to the WIFI status +#define LED_MODE_FOLLOW 2 // LED will follow state of linked relay (check RELAY#_LED) +#define LED_MODE_FOLLOW_INVERSE 3 // LED will follow the opposite state of linked relay (check RELAY#_LED) +#define LED_MODE_FINDME 4 // LED will be ON if all relays are OFF +#define LED_MODE_FINDME_WIFI 5 // A mixture between WIFI and FINDME +#define LED_MODE_ON 6 // LED always ON +#define LED_MODE_OFF 7 // LED always OFF +#define LED_MODE_RELAY 8 // If any relay is ON, LED will be ON, otherwise OFF +#define LED_MODE_RELAY_WIFI 9 // A mixture between WIFI and RELAY, the reverse of MIXED + +// ----------------------------------------------------------------------------- +// UI +// ----------------------------------------------------------------------------- + +#define UI_TAG_INPUT 0 +#define UI_TAG_CHECKBOX 1 +#define UI_TAG_SELECT 2 + +#define WEB_MODE_NORMAL 0 +#define WEB_MODE_PASSWORD 1 + +// ----------------------------------------------------------------------------- +// LIGHT +// ----------------------------------------------------------------------------- + +// Available light providers +#define LIGHT_PROVIDER_NONE 0 +#define LIGHT_PROVIDER_MY92XX 1 // works with MY9291 and MY9231 +#define LIGHT_PROVIDER_DIMMER 2 +#define LIGHT_PROVIDER_FASTLED 3 + +// ----------------------------------------------------------------------------- +// SCHEDULER +// ----------------------------------------------------------------------------- + +#define SCHEDULER_TYPE_SWITCH 1 +#define SCHEDULER_TYPE_DIM 2 + +// ----------------------------------------------------------------------------- +// IR +// ----------------------------------------------------------------------------- + +// IR Button modes +#define IR_BUTTON_MODE_NONE 0 +#define IR_BUTTON_MODE_RGB 1 +#define IR_BUTTON_MODE_HSV 2 +#define IR_BUTTON_MODE_BRIGHTER 3 +#define IR_BUTTON_MODE_STATE 4 +#define IR_BUTTON_MODE_EFFECT 5 +#define IR_BUTTON_MODE_TOGGLE 6 + +#define LIGHT_EFFECT_SOLID 0 +#define LIGHT_EFFECT_FLASH 1 +#define LIGHT_EFFECT_STROBE 2 +#define LIGHT_EFFECT_FADE 3 +#define LIGHT_EFFECT_SMOOTH 4 + +//------------------------------------------------------------------------------ +// RESET +//------------------------------------------------------------------------------ + +#define CUSTOM_RESET_HARDWARE 1 // Reset from hardware button +#define CUSTOM_RESET_WEB 2 // Reset from web interface +#define CUSTOM_RESET_TERMINAL 3 // Reset from terminal +#define CUSTOM_RESET_MQTT 4 // Reset via MQTT +#define CUSTOM_RESET_RPC 5 // Reset via RPC (HTTP) +#define CUSTOM_RESET_OTA 6 // Reset after successful OTA update +#define CUSTOM_RESET_HTTP 7 // Reset via HTTP GET +#define CUSTOM_RESET_NOFUSS 8 // Reset after successful NOFUSS update +#define CUSTOM_RESET_UPGRADE 9 // Reset after update from web interface +#define CUSTOM_RESET_FACTORY 10 // Factory reset from terminal + +#define CUSTOM_RESET_MAX 10 + +//------------------------------------------------------------------------------ +// ENVIRONMENTAL +//------------------------------------------------------------------------------ + +// American Society of Heating, Refrigerating and Air-Conditioning Engineers suggests a range of 45% - 55% humidity to manage health effects and illnesses. +// Comfortable: 30% - 60% +// Recommended: 45% - 55% +// High : 55% - 80% + +#define HUMIDITY_NORMAL 0 // > %30 +#define HUMIDITY_COMFORTABLE 1 // > %45 +#define HUMIDITY_DRY 2 // < %30 +#define HUMIDITY_WET 3 // > %70 + +// United States Environmental Protection Agency - UV Index Scale +// One UV Index unit is equivalent to 25 milliWatts per square meter. +#define UV_INDEX_LOW 0 // 0 to 2 means low danger from the sun's UV rays for the average person. +#define UV_INDEX_MODERATE 1 // 3 to 5 means moderate risk of harm from unprotected sun exposure. +#define UV_INDEX_HIGH 2 // 6 to 7 means high risk of harm from unprotected sun exposure. Protection against skin and eye damage is needed. +#define UV_INDEX_VERY_HIGH 3 // 8 to 10 means very high risk of harm from unprotected sun exposure. + // Take extra precautions because unprotected skin and eyes will be damaged and can burn quickly. +#define UV_INDEX_EXTREME 4 // 11 or more means extreme risk of harm from unprotected sun exposure. + // Take all precautions because unprotected skin and eyes can burn in minutes. + +//------------------------------------------------------------------------------ +// UNITS +//------------------------------------------------------------------------------ + +#define POWER_WATTS 0 +#define POWER_KILOWATTS 1 + +#define ENERGY_JOULES 0 +#define ENERGY_KWH 1 + +#define TMP_CELSIUS 0 +#define TMP_FAHRENHEIT 1 +#define TMP_KELVIN 2 + +//-------------------------------------------------------------------------------- +// Sensor ID +// These should remain over time, do not modify them, only add new ones at the end +//-------------------------------------------------------------------------------- + +#define SENSOR_DHTXX_ID 0x01 +#define SENSOR_DALLAS_ID 0x02 +#define SENSOR_EMON_ANALOG_ID 0x03 +#define SENSOR_EMON_ADC121_ID 0x04 +#define SENSOR_EMON_ADS1X15_ID 0x05 +#define SENSOR_HLW8012_ID 0x06 +#define SENSOR_V9261F_ID 0x07 +#define SENSOR_ECH1560_ID 0x08 +#define SENSOR_ANALOG_ID 0x09 +#define SENSOR_DIGITAL_ID 0x10 +#define SENSOR_EVENTS_ID 0x11 +#define SENSOR_PMSX003_ID 0x12 +#define SENSOR_BMX280_ID 0x13 +#define SENSOR_MHZ19_ID 0x14 +#define SENSOR_SI7021_ID 0x15 +#define SENSOR_SHT3X_I2C_ID 0x16 +#define SENSOR_BH1750_ID 0x17 +#define SENSOR_PZEM004T_ID 0x18 +#define SENSOR_AM2320_ID 0x19 +#define SENSOR_GUVAS12SD_ID 0x20 +#define SENSOR_CSE7766_ID 0x21 +#define SENSOR_TMP3X_ID 0x22 +#define SENSOR_HCSR04_ID 0x23 +#define SENSOR_SENSEAIR_ID 0x24 +#define SENSOR_GEIGER_ID 0x25 + +//-------------------------------------------------------------------------------- +// Magnitudes +//-------------------------------------------------------------------------------- + +#define MAGNITUDE_NONE 0 +#define MAGNITUDE_TEMPERATURE 1 +#define MAGNITUDE_HUMIDITY 2 +#define MAGNITUDE_PRESSURE 3 +#define MAGNITUDE_CURRENT 4 +#define MAGNITUDE_VOLTAGE 5 +#define MAGNITUDE_POWER_ACTIVE 6 +#define MAGNITUDE_POWER_APPARENT 7 +#define MAGNITUDE_POWER_REACTIVE 8 +#define MAGNITUDE_POWER_FACTOR 9 +#define MAGNITUDE_ENERGY 10 +#define MAGNITUDE_ENERGY_DELTA 11 +#define MAGNITUDE_ANALOG 12 +#define MAGNITUDE_DIGITAL 13 +#define MAGNITUDE_EVENTS 14 +#define MAGNITUDE_PM1dot0 15 +#define MAGNITUDE_PM2dot5 16 +#define MAGNITUDE_PM10 17 +#define MAGNITUDE_CO2 18 +#define MAGNITUDE_LUX 19 +#define MAGNITUDE_UV 20 +#define MAGNITUDE_DISTANCE 21 +#define MAGNITUDE_HCHO 22 +#define MAGNITUDE_GEIGER_CPM 23 +#define MAGNITUDE_GEIGER_SIEVERT 24 + +#define MAGNITUDE_MAX 25 diff --git a/code/espurna/config/version.h b/code/espurna/config/version.h index f64ac09f..6f2333e7 100644 --- a/code/espurna/config/version.h +++ b/code/espurna/config/version.h @@ -1,5 +1,6 @@ #define APP_NAME "ESPURNA" -#define APP_VERSION "1.11.2" +#define APP_VERSION "1.13.0c" +#define APP_REVISION "db84006" #define APP_AUTHOR "xose.perez@gmail.com" #define APP_WEBSITE "http://tinkerman.cat" #define CFG_VERSION 3 diff --git a/code/espurna/data/index.html.gz b/code/espurna/data/index.html.gz index bc0a01ee..1186b4a3 100644 Binary files a/code/espurna/data/index.html.gz and b/code/espurna/data/index.html.gz differ diff --git a/code/espurna/debug.ino b/code/espurna/debug.ino index 29873719..7eea7ccb 100644 --- a/code/espurna/debug.ino +++ b/code/espurna/debug.ino @@ -2,7 +2,7 @@ DEBUG MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -10,6 +10,7 @@ Copyright (C) 2016-2017 by Xose Pérez #include #include +#include extern "C" { #include "user_interface.h" @@ -17,79 +18,151 @@ extern "C" { #if DEBUG_UDP_SUPPORT #include -WiFiUDP udpDebug; +WiFiUDP _udp_debug; +#if DEBUG_UDP_PORT == 514 +char _udp_syslog_header[40] = {0}; +#endif #endif -void debugSend(const char * format, ...) { +void _debugSend(char * message) { - va_list args; - va_start(args, format); - char test[1]; - int len = ets_vsnprintf(test, 1, format, args) + 1; - char * buffer = new char[len]; - ets_vsnprintf(buffer, len, format, args); - va_end(args); + bool pause = false; + + #if DEBUG_ADD_TIMESTAMP + static bool add_timestamp = true; + char timestamp[10] = {0}; + if (add_timestamp) snprintf_P(timestamp, sizeof(timestamp), PSTR("[%06lu] "), millis() % 1000000); + add_timestamp = (message[strlen(message)-1] == 10) || (message[strlen(message)-1] == 13); + #endif #if DEBUG_SERIAL_SUPPORT - DEBUG_PORT.printf(buffer); + #if DEBUG_ADD_TIMESTAMP + DEBUG_PORT.printf(timestamp); + #endif + DEBUG_PORT.printf(message); #endif #if DEBUG_UDP_SUPPORT #if SYSTEM_CHECK_ENABLED if (systemCheck()) { #endif - udpDebug.beginPacket(DEBUG_UDP_IP, DEBUG_UDP_PORT); - udpDebug.write(buffer); - udpDebug.endPacket(); - delay(1); + _udp_debug.beginPacket(DEBUG_UDP_IP, DEBUG_UDP_PORT); + #if DEBUG_UDP_PORT == 514 + _udp_debug.write(_udp_syslog_header); + #endif + _udp_debug.write(message); + _udp_debug.endPacket(); + pause = true; #if SYSTEM_CHECK_ENABLED } #endif #endif #if DEBUG_TELNET_SUPPORT - _telnetWrite(buffer, strlen(buffer)); + #if DEBUG_ADD_TIMESTAMP + _telnetWrite(timestamp, strlen(timestamp)); + #endif + _telnetWrite(message, strlen(message)); + pause = true; + #endif + + #if DEBUG_WEB_SUPPORT + if (wsConnected() && (getFreeHeap() > 10000)) { + DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(1) + strlen(message) + 17); + JsonObject &root = jsonBuffer.createObject(); + #if DEBUG_ADD_TIMESTAMP + char buffer[strlen(timestamp) + strlen(message) + 1]; + snprintf_P(buffer, sizeof(buffer), "%s%s", timestamp, message); + root.set("weblog", buffer); + #else + root.set("weblog", message); + #endif + String out; + root.printTo(out); + jsonBuffer.clear(); + + wsSend(out.c_str()); + pause = true; + } #endif - free(buffer); + if (pause) optimistic_yield(100); } -void debugSend_P(PGM_P format, ...) { +// ----------------------------------------------------------------------------- - char f[DEBUG_FORMAT_MAX_LENGTH+1]; - memcpy_P(f, format, DEBUG_FORMAT_MAX_LENGTH); +void debugSend(const char * format, ...) { va_list args; va_start(args, format); char test[1]; - int len = ets_vsnprintf(test, 1, f, args) + 1; + int len = ets_vsnprintf(test, 1, format, args) + 1; char * buffer = new char[len]; - ets_vsnprintf(buffer, len, f, args); + ets_vsnprintf(buffer, len, format, args); va_end(args); - #if DEBUG_SERIAL_SUPPORT - DEBUG_PORT.printf(buffer); - #endif + _debugSend(buffer); - #if DEBUG_UDP_SUPPORT - #if SYSTEM_CHECK_ENABLED - if (systemCheck()) { - #endif - udpDebug.beginPacket(DEBUG_UDP_IP, DEBUG_UDP_PORT); - udpDebug.write(buffer); - udpDebug.endPacket(); - delay(1); - #if SYSTEM_CHECK_ENABLED + delete[] buffer; + +} + +void debugSend_P(PGM_P format_P, ...) { + + char format[strlen_P(format_P)+1]; + memcpy_P(format, format_P, sizeof(format)); + + va_list args; + va_start(args, format_P); + char test[1]; + int len = ets_vsnprintf(test, 1, format, args) + 1; + char * buffer = new char[len]; + ets_vsnprintf(buffer, len, format, args); + va_end(args); + + _debugSend(buffer); + + delete[] buffer; + +} + +#if DEBUG_WEB_SUPPORT + +void debugWebSetup() { + + wsOnSendRegister([](JsonObject& root) { + root["dbgVisible"] = 1; + }); + + wsOnActionRegister([](uint32_t client_id, const char * action, JsonObject& data) { + if (strcmp(action, "dbgcmd") == 0) { + const char* command = data.get("command"); + char buffer[strlen(command) + 2]; + snprintf(buffer, sizeof(buffer), "%s\n", command); + settingsInject((void*) buffer, strlen(buffer)); } - #endif - #endif + }); - #if DEBUG_TELNET_SUPPORT - _telnetWrite(buffer, strlen(buffer)); + #if DEBUG_UDP_SUPPORT + #if DEBUG_UDP_PORT == 514 + snprintf_P(_udp_syslog_header, sizeof(_udp_syslog_header), PSTR("<%u>%s ESPurna[0]: "), DEBUG_UDP_FAC_PRI, getSetting("hostname").c_str()); + #endif #endif - free(buffer); + +} + +#endif // DEBUG_WEB_SUPPORT + +void debugSetup() { + + #if DEBUG_SERIAL_SUPPORT + DEBUG_PORT.begin(SERIAL_BAUDRATE); + #if DEBUG_ESP_WIFI + DEBUG_PORT.setDebugOutput(true); + #endif + #endif } @@ -141,31 +214,31 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack // write crash time to EEPROM uint32_t crash_time = millis(); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); // write reset info to EEPROM - EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON, rst_info->reason); - EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE, rst_info->exccause); + EEPROMr.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON, rst_info->reason); + EEPROMr.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE, rst_info->exccause); // write epc1, epc2, epc3, excvaddr and depc to EEPROM - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, rst_info->epc1); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, rst_info->epc2); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, rst_info->epc3); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, rst_info->excvaddr); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, rst_info->depc); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, rst_info->epc1); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, rst_info->epc2); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, rst_info->epc3); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, rst_info->excvaddr); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, rst_info->depc); // write stack start and end address to EEPROM - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); // write stack trace to EEPROM int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE; for (uint32_t i = stack_start; i < stack_end; i++) { byte* byteValue = (byte*) i; - EEPROM.write(current_address++, *byteValue); + EEPROMr.write(current_address++, *byteValue); } - EEPROM.commit(); + EEPROMr.commit(); } @@ -174,8 +247,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack */ void debugClearCrashInfo() { uint32_t crash_time = 0xFFFFFFFF; - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); - EEPROM.commit(); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); + EEPROMr.commit(); } /** @@ -184,28 +257,28 @@ void debugClearCrashInfo() { void debugDumpCrashInfo() { uint32_t crash_time; - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); if ((crash_time == 0) || (crash_time == 0xFFFFFFFF)) { DEBUG_MSG_P(PSTR("[DEBUG] No crash info\n")); return; } - DEBUG_MSG_P(PSTR("[DEBUG] Crash at %ld ms\n"), crash_time); - DEBUG_MSG_P(PSTR("[DEBUG] Reason of restart: %d\n"), EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON)); - DEBUG_MSG_P(PSTR("[DEBUG] Exception cause: %d\n"), EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE)); + DEBUG_MSG_P(PSTR("[DEBUG] Latest crash was at %lu ms after boot\n"), crash_time); + DEBUG_MSG_P(PSTR("[DEBUG] Reason of restart: %u\n"), EEPROMr.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON)); + DEBUG_MSG_P(PSTR("[DEBUG] Exception cause: %u\n"), EEPROMr.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE)); uint32_t epc1, epc2, epc3, excvaddr, depc; - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, epc1); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, epc2); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, epc3); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, excvaddr); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, depc); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, epc1); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, epc2); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, epc3); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, excvaddr); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, depc); DEBUG_MSG_P(PSTR("[DEBUG] epc1=0x%08x epc2=0x%08x epc3=0x%08x\n"), epc1, epc2, epc3); DEBUG_MSG_P(PSTR("[DEBUG] excvaddr=0x%08x depc=0x%08x\n"), excvaddr, depc); uint32_t stack_start, stack_end; - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); DEBUG_MSG_P(PSTR("[DEBUG] >>>stack>>>\n[DEBUG] ")); int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE; int16_t stack_len = stack_end - stack_start; @@ -213,7 +286,7 @@ void debugDumpCrashInfo() { for (int16_t i = 0; i < stack_len; i += 0x10) { DEBUG_MSG_P(PSTR("%08x: "), stack_start + i); for (byte j = 0; j < 4; j++) { - EEPROM.get(current_address, stack_trace); + EEPROMr.get(current_address, stack_trace); DEBUG_MSG_P(PSTR("%08x "), stack_trace); current_address += 4; } @@ -222,4 +295,5 @@ void debugDumpCrashInfo() { DEBUG_MSG_P(PSTR("<< +Copyright (C) 2016-2018 by Xose Pérez */ @@ -11,16 +11,13 @@ Copyright (C) 2016-2017 by Xose Pérez #include bool _dcz_enabled = false; -unsigned long _dcz_skip_time = 0; -unsigned long _dcz_last_idx = 0; -unsigned long _dcz_last_time = 0; //------------------------------------------------------------------------------ // Private methods //------------------------------------------------------------------------------ -int _domoticzRelay(unsigned int idx) { - for (int relayID=0; relayID= 0) { - - // Skip message if recursive - if (_domoticzSkip(idx)) return; - - unsigned long value = root["nvalue"]; - DEBUG_MSG_P(PSTR("[DOMOTICZ] Received value %d for IDX %d\n"), value, idx); + unsigned char value = root["nvalue"]; + DEBUG_MSG_P(PSTR("[DOMOTICZ] Received value %u for IDX %u\n"), value, idx); relayStatus(relayID, value == 1); - } } @@ -89,16 +80,21 @@ void _domoticzMqtt(unsigned int type, const char * topic, const char * payload) }; +#if WEB_SUPPORT + +bool _domoticzWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "dcz", 3) == 0); +} + void _domoticzWebSocketOnSend(JsonObject& root) { root["dczVisible"] = 1; root["dczEnabled"] = getSetting("dczEnabled", DOMOTICZ_ENABLED).toInt() == 1; - root["dczSkip"] = getSetting("dczSkip", DOMOTICZ_SKIP_TIME); root["dczTopicIn"] = getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC); root["dczTopicOut"] = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC); - JsonArray& relays = root.createNestedArray("dczRelayIdx"); - for (byte i=0; i void domoticzSend(const char * key, T nvalue, const char * if (!_dcz_enabled) return; unsigned int idx = getSetting(key).toInt(); if (idx > 0) { - - // Skip message if recursive - if (_domoticzSkip(idx)) return; - char payload[128]; - snprintf(payload, sizeof(payload), "{\"idx\": %d, \"nvalue\": %s, \"svalue\": \"%s\"}", idx, String(nvalue).c_str(), svalue); + snprintf(payload, sizeof(payload), "{\"idx\": %u, \"nvalue\": %s, \"svalue\": \"%s\"}", idx, String(nvalue).c_str(), svalue); mqttSendRaw(getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC).c_str(), payload); - } } @@ -144,16 +137,22 @@ template void domoticzSend(const char * key, T nvalue) { domoticzSend(key, nvalue, ""); } -void domoticzSendRelay(unsigned int relayID) { +void domoticzSendRelay(unsigned char relayID) { if (!_dcz_enabled) return; char buffer[15]; - snprintf_P(buffer, sizeof(buffer), PSTR("dczRelayIdx%d"), relayID); + snprintf_P(buffer, sizeof(buffer), PSTR("dczRelayIdx%u"), relayID); domoticzSend(buffer, relayStatus(relayID) ? "1" : "0"); } -int domoticzIdx(unsigned int relayID) { +void domoticzSendRelays() { + for (uint8_t relayID=0; relayID < relayCount(); relayID++) { + domoticzSendRelay(relayID); + } +} + +unsigned int domoticzIdx(unsigned char relayID) { char buffer[15]; - snprintf_P(buffer, sizeof(buffer), PSTR("dczRelayIdx%d"), relayID); + snprintf_P(buffer, sizeof(buffer), PSTR("dczRelayIdx%u"), relayID); return getSetting(buffer).toInt(); } @@ -162,6 +161,7 @@ void domoticzSetup() { #if WEB_SUPPORT wsOnSendRegister(_domoticzWebSocketOnSend); wsOnAfterParseRegister(_domoticzConfigure); + wsOnReceiveRegister(_domoticzWebSocketOnReceive); #endif mqttRegister(_domoticzMqtt); } diff --git a/code/espurna/eeprom.ino b/code/espurna/eeprom.ino new file mode 100644 index 00000000..2e79fcbb --- /dev/null +++ b/code/espurna/eeprom.ino @@ -0,0 +1,86 @@ +/* + +EEPROM MODULE + +*/ + +#include + +// ----------------------------------------------------------------------------- + +bool eepromRotate(bool value) { + // Enable/disable EEPROM rotation only if we are using more sectors than the + // reserved by the memory layout + if (EEPROMr.size() > EEPROMr.reserved()) { + if (value) { + DEBUG_MSG_P(PSTR("[EEPROM] Reenabling EEPROM rotation\n")); + } else { + DEBUG_MSG_P(PSTR("[EEPROM] Disabling EEPROM rotation\n")); + } + EEPROMr.rotate(value); + } +} + +String eepromSectors() { + String response; + for (uint32_t i = 0; i < EEPROMr.size(); i++) { + if (i > 0) response = response + String(", "); + response = response + String(EEPROMr.base() - i); + } + return response; +} + +#if TERMINAL_SUPPORT + +void _eepromInitCommands() { + + settingsRegisterCommand(F("EEPROM.DUMP"), [](Embedis* e) { + EEPROMr.dump(settingsSerial()); + DEBUG_MSG_P(PSTR("\n+OK\n")); + }); + + settingsRegisterCommand(F("FLASH.DUMP"), [](Embedis* e) { + if (e->argc < 2) { + DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); + return; + } + uint32_t sector = String(e->argv[1]).toInt(); + uint32_t max = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; + if (sector >= max) { + DEBUG_MSG_P(PSTR("-ERROR: Sector out of range\n")); + return; + } + EEPROMr.dump(settingsSerial(), sector); + DEBUG_MSG_P(PSTR("\n+OK\n")); + }); + +} + +#endif + +// ----------------------------------------------------------------------------- + +void eepromSetup() { + + #ifdef EEPROM_ROTATE_SECTORS + EEPROMr.size(EEPROM_ROTATE_SECTORS); + #else + // If the memory layout has more than one sector reserved use those, + // otherwise calculate pool size based on memory size. + if (EEPROMr.size() == 1) { + if (EEPROMr.last() > 1000) { // 4Mb boards + EEPROMr.size(4); + } else if (EEPROMr.last() > 250) { // 1Mb boards + EEPROMr.size(2); + } + } + #endif + + EEPROMr.offset(EEPROM_ROTATE_DATA); + EEPROMr.begin(EEPROM_SIZE); + + #if TERMINAL_SUPPORT + _eepromInitCommands(); + #endif + +} diff --git a/code/espurna/espurna.ino b/code/espurna/espurna.ino index 24a35b8e..def70f6b 100644 --- a/code/espurna/espurna.ino +++ b/code/espurna/espurna.ino @@ -2,7 +2,7 @@ ESPurna -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,321 +20,95 @@ along with this program. If not, see . */ #include "config/all.h" -#include +#include + +std::vector _loop_callbacks; // ----------------------------------------------------------------------------- -// METHODS +// REGISTER // ----------------------------------------------------------------------------- -unsigned long _loopDelay = 0; - -void hardwareSetup() { - - EEPROM.begin(EEPROM_SIZE); - - #if DEBUG_SERIAL_SUPPORT - DEBUG_PORT.begin(SERIAL_BAUDRATE); - #if DEBUG_ESP_WIFI - DEBUG_PORT.setDebugOutput(true); - #endif - #elif defined(SERIAL_BAUDRATE) - Serial.begin(SERIAL_BAUDRATE); - #endif - - #if SPIFFS_SUPPORT - SPIFFS.begin(); - #endif - - #if defined(ESPLIVE) - //The ESPLive has an ADC MUX which needs to be configured. - pinMode(16, OUTPUT); - digitalWrite(16, HIGH); //Defualt CT input (pin B, solder jumper B) - #endif - -} - -void hardwareLoop() { - - // Heartbeat - static unsigned long last_uptime = 0; - static bool on_connect = true; - - bool send = (last_uptime == 0); - send = send || (millis() - last_uptime > HEARTBEAT_INTERVAL); - if (mqttConnected()) { - send = send || on_connect; - } else { - on_connect = true; - } - - if (send) { - last_uptime = millis(); - if (mqttConnected()) on_connect = false; - heartbeat(); - } - +void espurnaRegisterLoop(void (*callback)()) { + _loop_callbacks.push_back(callback); } // ----------------------------------------------------------------------------- // BOOTING // ----------------------------------------------------------------------------- -unsigned int sectors(size_t size) { - return (int) (size + SPI_FLASH_SEC_SIZE - 1) / SPI_FLASH_SEC_SIZE; -} - -void welcome() { - - DEBUG_MSG_P(PSTR("\n\n")); - DEBUG_MSG_P(PSTR("[INIT] %s %s\n"), (char *) APP_NAME, (char *) APP_VERSION); - DEBUG_MSG_P(PSTR("[INIT] %s\n"), (char *) APP_AUTHOR); - DEBUG_MSG_P(PSTR("[INIT] %s\n\n"), (char *) APP_WEBSITE); - DEBUG_MSG_P(PSTR("[INIT] CPU chip ID: 0x%06X\n"), ESP.getChipId()); - DEBUG_MSG_P(PSTR("[INIT] CPU frequency: %d MHz\n"), ESP.getCpuFreqMHz()); - DEBUG_MSG_P(PSTR("[INIT] SDK version: %s\n"), ESP.getSdkVersion()); - DEBUG_MSG_P(PSTR("[INIT] Core version: %s\n"), getCoreVersion().c_str()); - DEBUG_MSG_P(PSTR("[INIT] Core revision: %s\n"), getCoreRevision().c_str()); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - FlashMode_t mode = ESP.getFlashChipMode(); - DEBUG_MSG_P(PSTR("[INIT] Flash chip ID: 0x%06X\n"), ESP.getFlashChipId()); - DEBUG_MSG_P(PSTR("[INIT] Flash speed: %u Hz\n"), ESP.getFlashChipSpeed()); - DEBUG_MSG_P(PSTR("[INIT] Flash mode: %s\n"), mode == FM_QIO ? "QIO" : mode == FM_QOUT ? "QOUT" : mode == FM_DIO ? "DIO" : mode == FM_DOUT ? "DOUT" : "UNKNOWN"); - DEBUG_MSG_P(PSTR("\n")); - DEBUG_MSG_P(PSTR("[INIT] Flash sector size: %8u bytes\n"), SPI_FLASH_SEC_SIZE); - DEBUG_MSG_P(PSTR("[INIT] Flash size (CHIP): %8u bytes\n"), ESP.getFlashChipRealSize()); - DEBUG_MSG_P(PSTR("[INIT] Flash size (SDK): %8u bytes / %4d sectors\n"), ESP.getFlashChipSize(), sectors(ESP.getFlashChipSize())); - DEBUG_MSG_P(PSTR("[INIT] Firmware size: %8u bytes / %4d sectors\n"), ESP.getSketchSize(), sectors(ESP.getSketchSize())); - DEBUG_MSG_P(PSTR("[INIT] OTA size: %8u bytes / %4d sectors\n"), ESP.getFreeSketchSpace(), sectors(ESP.getFreeSketchSpace())); - #if SPIFFS_SUPPORT - FSInfo fs_info; - bool fs = SPIFFS.info(fs_info); - if (fs) { - DEBUG_MSG_P(PSTR("[INIT] SPIFFS size: %8u bytes / %4d sectors\n"), fs_info.totalBytes, sectors(fs_info.totalBytes)); - } - #else - DEBUG_MSG_P(PSTR("[INIT] SPIFFS size: %8u bytes / %4d sectors\n"), 0, 0); - #endif - DEBUG_MSG_P(PSTR("[INIT] EEPROM size: %8u bytes / %4d sectors\n"), settingsMaxSize(), sectors(settingsMaxSize())); - DEBUG_MSG_P(PSTR("[INIT] Empty space: %8u bytes / 4 sectors\n"), 4 * SPI_FLASH_SEC_SIZE); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - #if SPIFFS_SUPPORT - if (fs) { - DEBUG_MSG_P(PSTR("[INIT] SPIFFS total size: %8u bytes\n"), fs_info.totalBytes); - DEBUG_MSG_P(PSTR("[INIT] used size: %8u bytes\n"), fs_info.usedBytes); - DEBUG_MSG_P(PSTR("[INIT] block size: %8u bytes\n"), fs_info.blockSize); - DEBUG_MSG_P(PSTR("[INIT] page size: %8u bytes\n"), fs_info.pageSize); - DEBUG_MSG_P(PSTR("[INIT] max files: %8u\n"), fs_info.maxOpenFiles); - DEBUG_MSG_P(PSTR("[INIT] max length: %8u\n"), fs_info.maxPathLength); - } else { - DEBUG_MSG_P(PSTR("[INIT] No SPIFFS partition\n")); - } - DEBUG_MSG_P(PSTR("\n")); - #endif +void setup() { // ------------------------------------------------------------------------- - - DEBUG_MSG_P(PSTR("[INIT] MANUFACTURER: %s\n"), MANUFACTURER); - DEBUG_MSG_P(PSTR("[INIT] DEVICE: %s\n"), DEVICE); - DEBUG_MSG_P(PSTR("[INIT] SUPPORT:")); - - #if ALEXA_SUPPORT - DEBUG_MSG_P(PSTR(" ALEXA")); - #endif - #if DEBUG_SERIAL_SUPPORT - DEBUG_MSG_P(PSTR(" DEBUG_SERIAL")); - #endif - #if DEBUG_TELNET_SUPPORT - DEBUG_MSG_P(PSTR(" DEBUG_TELNET")); - #endif - #if DEBUG_UDP_SUPPORT - DEBUG_MSG_P(PSTR(" DEBUG_UDP")); - #endif - #if DOMOTICZ_SUPPORT - DEBUG_MSG_P(PSTR(" DOMOTICZ")); - #endif - #if HOMEASSISTANT_SUPPORT - DEBUG_MSG_P(PSTR(" HOMEASSISTANT")); - #endif - #if I2C_SUPPORT - DEBUG_MSG_P(PSTR(" I2C")); - #endif - #if INFLUXDB_SUPPORT - DEBUG_MSG_P(PSTR(" INFLUXDB")); - #endif - #if LLMNR_SUPPORT - DEBUG_MSG_P(PSTR(" LLMNR")); - #endif - #if MDNS_SUPPORT - DEBUG_MSG_P(PSTR(" MDNS")); - #endif - #if NETBIOS_SUPPORT - DEBUG_MSG_P(PSTR(" NETBIOS")); - #endif - #if NOFUSS_SUPPORT - DEBUG_MSG_P(PSTR(" NOFUSS")); - #endif - #if NTP_SUPPORT - DEBUG_MSG_P(PSTR(" NTP")); - #endif - #if RF_SUPPORT - DEBUG_MSG_P(PSTR(" RF")); - #endif - #if SENSOR_SUPPORT - DEBUG_MSG_P(PSTR(" SENSOR")); - #endif - #if SPIFFS_SUPPORT - DEBUG_MSG_P(PSTR(" SPIFFS")); - #endif - #if SSDP_SUPPORT - DEBUG_MSG_P(PSTR(" SSDP")); - #endif - #if TELNET_SUPPORT - DEBUG_MSG_P(PSTR(" TELNET")); - #endif - #if TERMINAL_SUPPORT - DEBUG_MSG_P(PSTR(" TERMINAL")); - #endif - #if WEB_SUPPORT - DEBUG_MSG_P(PSTR(" WEB")); - #endif - - #if SENSOR_SUPPORT - - DEBUG_MSG_P(PSTR("\n[INIT] SENSORS:")); - - #if ANALOG_SUPPORT - DEBUG_MSG_P(PSTR(" ANALOG")); - #endif - #if BMX280_SUPPORT - DEBUG_MSG_P(PSTR(" BMX280")); - #endif - #if DALLAS_SUPPORT - DEBUG_MSG_P(PSTR(" DALLAS")); - #endif - #if DHT_SUPPORT - DEBUG_MSG_P(PSTR(" DHTXX")); - #endif - #if DIGITAL_SUPPORT - DEBUG_MSG_P(PSTR(" DIGITAL")); - #endif - #if ECH1560_SUPPORT - DEBUG_MSG_P(PSTR(" ECH1560")); - #endif - #if EMON_ADC121_SUPPORT - DEBUG_MSG_P(PSTR(" EMON_ADC121")); - #endif - #if EMON_ADS1X15_SUPPORT - DEBUG_MSG_P(PSTR(" EMON_ADX1X15")); - #endif - #if EMON_ANALOG_SUPPORT - DEBUG_MSG_P(PSTR(" EMON_ANALOG")); - #endif - #if EVENTS_SUPPORT - DEBUG_MSG_P(PSTR(" EVENTS")); - #endif - #if HLW8012_SUPPORT - DEBUG_MSG_P(PSTR(" HLW8012")); - #endif - #if MHZ19_SUPPORT - DEBUG_MSG_P(PSTR(" MHZ19")); - #endif - #if PMSX003_SUPPORT - DEBUG_MSG_P(PSTR(" PMSX003")); - #endif - #if SHT3X_I2C_SUPPORT - DEBUG_MSG_P(PSTR(" SHT3X_I2C")); - #endif - #if SI7021_SUPPORT - DEBUG_MSG_P(PSTR(" SI7021")); - #endif - #if V9261F_SUPPORT - DEBUG_MSG_P(PSTR(" V9261F")); - #endif - - #endif // SENSOR_SUPPORT - - DEBUG_MSG_P(PSTR("\n\n")); - + // Basic modules, will always run // ------------------------------------------------------------------------- - unsigned char reason = resetReason(); - if (reason > 0) { - char buffer[32]; - strcpy_P(buffer, custom_reset_string[reason-1]); - DEBUG_MSG_P(PSTR("[INIT] Last reset reason: %s\n"), buffer); - } else { - DEBUG_MSG_P(PSTR("[INIT] Last reset reason: %s\n"), (char *) ESP.getResetReason().c_str()); - } - - DEBUG_MSG_P(PSTR("[INIT] Free heap: %u bytes\n"), getFreeHeap()); - #if ADC_VCC_ENABLED - DEBUG_MSG_P(PSTR("[INIT] Power: %d mV\n"), ESP.getVcc()); + // Serial debug + #if DEBUG_SUPPORT + debugSetup(); #endif - DEBUG_MSG_P(PSTR("[INIT] Power saving delay value: %lu ms\n"), _loopDelay); - DEBUG_MSG_P(PSTR("\n")); - -} - -void setup() { - - // Init EEPROM, Serial and SPIFFS - hardwareSetup(); - - // Question system stability - #if SYSTEM_CHECK_ENABLED - systemCheck(false); - #endif + // Init EEPROM + eepromSetup(); + + // Init Serial, SPIFFS and system check + systemSetup(); // Init persistance and terminal features settingsSetup(); + + // Hostname & board name initialization if (getSetting("hostname").length() == 0) { - setSetting("hostname", getIdentifier()); + setDefaultHostname(); } - - // Cache loop delay value to speed things (recommended max 250ms) - _loopDelay = atol(getSetting("loopDelay", LOOP_DELAY_TIME).c_str()); + setBoardName(); // Show welcome message and system configuration - welcome(); + info(); - // Basic modules, will always run wifiSetup(); otaSetup(); #if TELNET_SUPPORT telnetSetup(); #endif - // Do not run the next services if system is flagged stable + // ------------------------------------------------------------------------- + // Check if system is stable + // ------------------------------------------------------------------------- + #if SYSTEM_CHECK_ENABLED if (!systemCheck()) return; #endif + // ------------------------------------------------------------------------- + // Next modules will be only loaded if system is flagged as stable + // ------------------------------------------------------------------------- + // Init webserver required before any module that uses API #if WEB_SUPPORT webSetup(); wsSetup(); apiSetup(); + #if DEBUG_WEB_SUPPORT + debugWebSetup(); + #endif #endif + // lightSetup must be called before relaySetup #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE lightSetup(); #endif + relaySetup(); buttonSetup(); ledSetup(); #if MQTT_SUPPORT mqttSetup(); #endif - - #if MDNS_SUPPORT - mdnsSetup(); + #if MDNS_SERVER_SUPPORT + mdnsServerSetup(); + #endif + #if MDNS_CLIENT_SUPPORT + mdnsClientSetup(); #endif #if LLMNR_SUPPORT llmnrSetup(); @@ -350,12 +124,7 @@ void setup() { #endif #if I2C_SUPPORT i2cSetup(); - #if I2C_CLEAR_BUS - i2cClearBus(); - #endif - i2cScan(); #endif - #ifdef ITEAD_SONOFF_RFBRIDGE rfbSetup(); #endif @@ -368,6 +137,9 @@ void setup() { #if INFLUXDB_SUPPORT idbSetup(); #endif + #if THINGSPEAK_SUPPORT + tspkSetup(); + #endif #if RF_SUPPORT rfSetup(); #endif @@ -383,6 +155,18 @@ void setup() { #if SENSOR_SUPPORT sensorSetup(); #endif + #if SCHEDULER_SUPPORT + schSetup(); + #endif + #if UART_MQTT_SUPPORT + uartmqttSetup(); + #endif + + + // 3rd party code hook + #if USE_EXTRA + extraSetup(); + #endif // Prepare configuration for version 2.0 migrate(); @@ -393,53 +177,9 @@ void setup() { void loop() { - hardwareLoop(); - settingsLoop(); - wifiLoop(); - otaLoop(); - - #if SYSTEM_CHECK_ENABLED - systemCheckLoop(); - // Do not run the next services if system is flagged stable - if (!systemCheck()) return; - #endif - - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - lightLoop(); - #endif - relayLoop(); - buttonLoop(); - ledLoop(); - #if MQTT_SUPPORT - mqttLoop(); - #endif - - #ifdef ITEAD_SONOFF_RFBRIDGE - rfbLoop(); - #endif - #if SSDP_SUPPORT - ssdpLoop(); - #endif - #if NTP_SUPPORT - ntpLoop(); - #endif - #if ALEXA_SUPPORT - alexaLoop(); - #endif - #if NOFUSS_SUPPORT - nofussLoop(); - #endif - #if RF_SUPPORT - rfLoop(); - #endif - #if IR_SUPPORT - irLoop(); - #endif - #if SENSOR_SUPPORT - sensorLoop(); - #endif - - // Power saving delay - delay(_loopDelay); + // Call registered loop callbacks + for (unsigned char i = 0; i < _loop_callbacks.size(); i++) { + (_loop_callbacks[i])(); + } } diff --git a/code/espurna/filters/BaseFilter.h b/code/espurna/filters/BaseFilter.h index f337c7a3..3ad2852e 100644 --- a/code/espurna/filters/BaseFilter.h +++ b/code/espurna/filters/BaseFilter.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Base Filter (other filters inherit from this) -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT diff --git a/code/espurna/filters/MaxFilter.h b/code/espurna/filters/MaxFilter.h index bf660322..9668fc95 100644 --- a/code/espurna/filters/MaxFilter.h +++ b/code/espurna/filters/MaxFilter.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Max Filter -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT diff --git a/code/espurna/filters/MedianFilter.h b/code/espurna/filters/MedianFilter.h index 98376e3f..1d34a309 100644 --- a/code/espurna/filters/MedianFilter.h +++ b/code/espurna/filters/MedianFilter.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Median Filter -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT diff --git a/code/espurna/filters/MovingAverageFilter.h b/code/espurna/filters/MovingAverageFilter.h index beb08c55..21ba66d4 100644 --- a/code/espurna/filters/MovingAverageFilter.h +++ b/code/espurna/filters/MovingAverageFilter.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Moving Average Filter -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT diff --git a/code/espurna/gpio.ino b/code/espurna/gpio.ino index c65e95b6..c69f437a 100644 --- a/code/espurna/gpio.ino +++ b/code/espurna/gpio.ino @@ -2,14 +2,14 @@ GPIO MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez */ unsigned int _gpio_locked = 0; bool gpioValid(unsigned char gpio) { - if (0 <= gpio && gpio <= 5) return true; + if (gpio <= 5) return true; if (12 <= gpio && gpio <= 15) return true; return false; } @@ -19,11 +19,11 @@ bool gpioGetLock(unsigned char gpio) { unsigned int mask = 1 << gpio; if ((_gpio_locked & mask) == 0) { _gpio_locked |= mask; - DEBUG_MSG_P(PSTR("[GPIO] GPIO%d locked\n"), gpio); + DEBUG_MSG_P(PSTR("[GPIO] GPIO%u locked\n"), gpio); return true; } } - DEBUG_MSG_P(PSTR("[GPIO] Failed getting lock for GPIO%d\n"), gpio); + DEBUG_MSG_P(PSTR("[GPIO] Failed getting lock for GPIO%u\n"), gpio); return false; } @@ -31,9 +31,9 @@ bool gpioReleaseLock(unsigned char gpio) { if (gpioValid(gpio)) { unsigned int mask = 1 << gpio; _gpio_locked &= ~mask; - DEBUG_MSG_P(PSTR("[GPIO] GPIO%d lock released\n"), gpio); + DEBUG_MSG_P(PSTR("[GPIO] GPIO%u lock released\n"), gpio); return true; } - DEBUG_MSG_P(PSTR("[GPIO] Failed releasing lock for GPIO%d\n"), gpio); + DEBUG_MSG_P(PSTR("[GPIO] Failed releasing lock for GPIO%u\n"), gpio); return false; } diff --git a/code/espurna/homeassistant.ino b/code/espurna/homeassistant.ino new file mode 100644 index 00000000..9b8c8934 --- /dev/null +++ b/code/espurna/homeassistant.ino @@ -0,0 +1,306 @@ +/* + +HOME ASSISTANT MODULE + +Copyright (C) 2017-2018 by Xose Pérez + +*/ + +#if HOMEASSISTANT_SUPPORT + +#include + +bool _haEnabled = false; +bool _haSendFlag = false; + +// ----------------------------------------------------------------------------- +// SENSORS +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT + +void _haSendMagnitude(unsigned char i, JsonObject& config) { + + unsigned char type = magnitudeType(i); + config["name"] = getSetting("hostname") + String(" ") + magnitudeTopic(type); + config.set("platform", "mqtt"); + config["state_topic"] = mqttTopic(magnitudeTopicIndex(i).c_str(), false); + config["unit_of_measurement"] = magnitudeUnits(type); + +} + +void _haSendMagnitudes() { + + for (unsigned char i=0; i 1) { + name += String(" #") + String(i); + } + + config.set("name", name); + config.set("platform", "mqtt"); + + if (relayCount()) { + config["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false); + config["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, true); + config["payload_on"] = String("1"); + config["payload_off"] = String("0"); + config["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false); + config["payload_available"] = String("1"); + config["payload_not_available"] = String("0"); + } + + #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + + if (i == 0) { + + if (lightHasColor()) { + config["brightness_state_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, false); + config["brightness_command_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, true); + config["rgb_state_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, false); + config["rgb_command_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, true); + config["color_temp_command_topic"] = mqttTopic(MQTT_TOPIC_MIRED, true); + } + + if (lightChannels() > 3) { + config["white_value_state_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, false); + config["white_value_command_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, true); + } + + } + + #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + +} + +void _haSendSwitches() { + + #if (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE) || (defined(ITEAD_SLAMPHER)) + String type = String("light"); + #else + String type = String("switch"); + #endif + + for (unsigned char i=0; i() + String("\n"); + } + output += "\n"; + + jsonBuffer.clear(); + + } + + #if SENSOR_SUPPORT + + for (unsigned char i=0; i() + String("\n"); + } + output += "\n"; + + jsonBuffer.clear(); + + } + + #endif + + return output; + +} + +void _haSend() { + + // Pending message to send? + if (!_haSendFlag) return; + + // Are we connected? + if (!mqttConnected()) return; + + DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n")); + + // Send messages + _haSendSwitches(); + #if SENSOR_SUPPORT + _haSendMagnitudes(); + #endif + + _haSendFlag = false; + +} + +void _haConfigure() { + bool enabled = getSetting("haEnabled", HOMEASSISTANT_ENABLED).toInt() == 1; + _haSendFlag = (enabled != _haEnabled); + _haEnabled = enabled; + _haSend(); +} + +#if WEB_SUPPORT + +bool _haWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "ha", 2) == 0); +} + +void _haWebSocketOnSend(JsonObject& root) { + root["haVisible"] = 1; + root["haPrefix"] = getSetting("haPrefix", HOMEASSISTANT_PREFIX); + root["haEnabled"] = getSetting("haEnabled", HOMEASSISTANT_ENABLED).toInt() == 1; +} + +void _haWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) { + if (strcmp(action, "haconfig") == 0) { + String output = _haGetConfig(); + output.replace(" ", " "); + output.replace("\n", "
"); + output = String("{\"haConfig\": \"") + output + String("\"}"); + wsSend(client_id, output.c_str()); + } +} + +#endif + +#if TERMINAL_SUPPORT + +void _haInitCommands() { + settingsRegisterCommand(F("HA.CONFIG"), [](Embedis* e) { + DEBUG_MSG(_haGetConfig().c_str()); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + settingsRegisterCommand(F("HA.SEND"), [](Embedis* e) { + setSetting("haEnabled", "1"); + _haConfigure(); + #if WEB_SUPPORT + wsSend(_haWebSocketOnSend); + #endif + DEBUG_MSG_P(PSTR("+OK\n")); + }); + settingsRegisterCommand(F("HA.CLEAR"), [](Embedis* e) { + setSetting("haEnabled", "0"); + _haConfigure(); + #if WEB_SUPPORT + wsSend(_haWebSocketOnSend); + #endif + DEBUG_MSG_P(PSTR("+OK\n")); + }); +} + +#endif + +// ----------------------------------------------------------------------------- + +void haSetup() { + + _haConfigure(); + + #if WEB_SUPPORT + wsOnSendRegister(_haWebSocketOnSend); + wsOnAfterParseRegister(_haConfigure); + wsOnActionRegister(_haWebSocketOnAction); + wsOnReceiveRegister(_haWebSocketOnReceive); + #endif + + // On MQTT connect check if we have something to send + mqttRegister([](unsigned int type, const char * topic, const char * payload) { + if (type == MQTT_CONNECT_EVENT) _haSend(); + }); + + #if TERMINAL_SUPPORT + _haInitCommands(); + #endif + + +} + +#endif // HOMEASSISTANT_SUPPORT diff --git a/code/espurna/homeassitant.ino b/code/espurna/homeassitant.ino deleted file mode 100644 index 24e9ed82..00000000 --- a/code/espurna/homeassitant.ino +++ /dev/null @@ -1,101 +0,0 @@ -/* - -HOME ASSISTANT MODULE - -Copyright (C) 2017 by Xose Pérez - -*/ - -#if HOMEASSISTANT_SUPPORT - -#include - -bool _haEnabled = false; - -// ----------------------------------------------------------------------------- - -void _haWebSocketOnSend(JsonObject& root) { - root["haVisible"] = 1; - root["haPrefix"] = getSetting("haPrefix", HOMEASSISTANT_PREFIX); -} - -void _haConfigure() { - bool enabled = getSetting("haEnabled", HOMEASSISTANT_ENABLED).toInt() == 1; - if (enabled != _haEnabled) haSend(enabled); - _haEnabled = enabled; -} - -// ----------------------------------------------------------------------------- - -void haSend(bool add) { - - DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n")); - - String output; - - if (add) { - - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.createObject(); - - root["name"] = getSetting("hostname"); - root["platform"] = "mqtt"; - - if (relayCount()) { - root["state_topic"] = getTopic(MQTT_TOPIC_RELAY, 0, false); - root["command_topic"] = getTopic(MQTT_TOPIC_RELAY, 0, true); - root["payload_on"] = String("1"); - root["payload_off"] = String("0"); - root["availability_topic"] = getTopic(MQTT_TOPIC_STATUS, false); - root["payload_available"] = String("1"); - root["payload_not_available"] = String("0"); - } - - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - - if (lightHasColor()) { - root["brightness_state_topic"] = getTopic(MQTT_TOPIC_BRIGHTNESS, false); - root["brightness_command_topic"] = getTopic(MQTT_TOPIC_BRIGHTNESS, true); - root["rgb_state_topic"] = getTopic(MQTT_TOPIC_COLOR_RGB, false); - root["rgb_command_topic"] = getTopic(MQTT_TOPIC_COLOR_RGB, true); - root["color_temp_command_topic"] = getTopic(MQTT_TOPIC_MIRED, true); - } - - if (lightChannels() > 3) { - root["white_value_state_topic"] = getTopic(MQTT_TOPIC_CHANNEL, 3, false); - root["white_value_command_topic"] = getTopic(MQTT_TOPIC_CHANNEL, 3, true); - } - - #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - - root.printTo(output); - } - - #if LIGHT_PROVIDER == LIGHT_PROVIDER_NONE - String component = String("switch"); - #else - String component = String("light"); - #endif - - String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) + - "/" + component + - "/" + getSetting("hostname") + - "/config"; - - mqttSendRaw(topic.c_str(), output.c_str()); - mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); - -} - -void haSetup() { - _haConfigure(); - #if WEB_SUPPORT - wsOnSendRegister(_haWebSocketOnSend); - wsOnAfterParseRegister(_haConfigure); - #endif - mqttRegister([](unsigned int type, const char * topic, const char * payload) { - if (type == MQTT_CONNECT_EVENT) haSend(_haEnabled); - }); -} - -#endif // HOMEASSISTANT_SUPPORT diff --git a/code/espurna/i2c.ino b/code/espurna/i2c.ino index ccbf27bb..8300929a 100644 --- a/code/espurna/i2c.ino +++ b/code/espurna/i2c.ino @@ -2,7 +2,7 @@ I2C MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez */ @@ -32,7 +32,7 @@ int _i2cClearbus(int sda, int scl) { pinMode(sda, INPUT_PULLUP); pinMode(scl, INPUT_PULLUP); - delay(2500); + nice_delay(2500); // Wait 2.5 secs. This is strictly only necessary on the first power // up of the DS3231 module to allow it to initialize properly, // but is also assists in reliable programming of FioV3 boards as it gives the @@ -68,7 +68,7 @@ int _i2cClearbus(int sda, int scl) { int counter = 20; while (scl_low && (counter > 0)) { counter--; - delay(100); + nice_delay(100); scl_low = (digitalRead(scl) == LOW); } @@ -104,6 +104,176 @@ int _i2cClearbus(int sda, int scl) { } +// --------------------------------------------------------------------- +// I2C API +// --------------------------------------------------------------------- + +#if I2C_USE_BRZO + +void i2c_wakeup(uint8_t address) { + brzo_i2c_start_transaction(_address, _i2c_scl_frequency); + brzo_i2c_end_transaction(); +} + +uint8_t i2c_write_uint8(uint8_t address, uint8_t value) { + uint8_t buffer[1] = {value}; + brzo_i2c_start_transaction(_address, _i2c_scl_frequency); + brzo_i2c_write_uint8(buffer, 1, false); + return brzo_i2c_end_transaction(); +} + +uint8_t i2c_write_buffer(uint8_t address, uint8_t * buffer, size_t len) { + brzo_i2c_start_transaction(_address, _i2c_scl_frequency); + brzo_i2c_write_uint8(buffer, len, false); + return brzo_i2c_end_transaction(); +} + +uint8_t i2c_read_uint8(uint8_t address) { + uint8_t buffer[1] = {reg}; + brzo_i2c_start_transaction(_address, _i2c_scl_frequency); + brzo_i2c_read(buffer, 1, false); + brzo_i2c_end_transaction(); + return buffer[0]; +}; + +uint8_t i2c_read_uint8(uint8_t address, uint8_t reg) { + uint8_t buffer[1] = {reg}; + brzo_i2c_start_transaction(_address, _i2c_scl_frequency); + brzo_i2c_write_uint8(buffer, 1, false); + brzo_i2c_read(buffer, 1, false); + brzo_i2c_end_transaction(); + return buffer[0]; +}; + +uint16_t i2c_read_uint16(uint8_t address) { + uint8_t buffer[2] = {reg, 0}; + brzo_i2c_start_transaction(_address, _i2c_scl_frequency); + brzo_i2c_read(buffer, 2, false); + brzo_i2c_end_transaction(); + return (buffer[0] * 256) | buffer[1]; +}; + +uint16_t i2c_read_uint16(uint8_t address, uint8_t reg) { + uint8_t buffer[2] = {reg, 0}; + brzo_i2c_start_transaction(_address, _i2c_scl_frequency); + brzo_i2c_write_uint8(buffer, 1, false); + brzo_i2c_read(buffer, 2, false); + brzo_i2c_end_transaction(); + return (buffer[0] * 256) | buffer[1]; +}; + +void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len) { + brzo_i2c_start_transaction(address, _i2c_scl_frequency); + brzo_i2c_read(buffer, len, false); + brzo_i2c_end_transaction(); +} + +#else // not I2C_USE_BRZO + +void i2c_wakeup(uint8_t address) { + Wire.beginTransmission((uint8_t) address); + Wire.endTransmission(); +} + +uint8_t i2c_write_uint8(uint8_t address, uint8_t value) { + Wire.beginTransmission((uint8_t) address); + Wire.write((uint8_t) value); + return Wire.endTransmission(); +} + +uint8_t i2c_write_buffer(uint8_t address, uint8_t * buffer, size_t len) { + Wire.beginTransmission((uint8_t) address); + Wire.write(buffer, len); + return Wire.endTransmission(); +} + +uint8_t i2c_read_uint8(uint8_t address) { + uint8_t value; + Wire.beginTransmission((uint8_t) address); + Wire.requestFrom((uint8_t) address, (uint8_t) 1); + value = Wire.read(); + Wire.endTransmission(); + return value; +}; + +uint8_t i2c_read_uint8(uint8_t address, uint8_t reg) { + uint8_t value; + Wire.beginTransmission((uint8_t) address); + Wire.write((uint8_t) reg); + Wire.endTransmission(); + Wire.requestFrom((uint8_t) address, (uint8_t) 1); + value = Wire.read(); + Wire.endTransmission(); + return value; +}; + +uint16_t i2c_read_uint16(uint8_t address) { + uint16_t value; + Wire.beginTransmission((uint8_t) address); + Wire.requestFrom((uint8_t) address, (uint8_t) 2); + value = (Wire.read() * 256) | Wire.read(); + Wire.endTransmission(); + return value; +}; + +uint16_t i2c_read_uint16(uint8_t address, uint8_t reg) { + uint16_t value; + Wire.beginTransmission((uint8_t) address); + Wire.write((uint8_t) reg); + Wire.endTransmission(); + Wire.requestFrom((uint8_t) address, (uint8_t) 2); + value = (Wire.read() * 256) | Wire.read(); + Wire.endTransmission(); + return value; +}; + +void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len) { + Wire.beginTransmission((uint8_t) address); + Wire.requestFrom(address, (uint8_t) len); + for (int i=0; i> 8) & 0xFF; + buffer[2] = (value >> 0) & 0xFF; + return i2c_write_buffer(address, buffer, 3); +} + +uint8_t i2c_write_uint16(uint8_t address, uint16_t value) { + uint8_t buffer[2]; + buffer[0] = (value >> 8) & 0xFF; + buffer[1] = (value >> 0) & 0xFF; + return i2c_write_buffer(address, buffer, 2); +} + +uint16_t i2c_read_uint16_le(uint8_t address, uint8_t reg) { + uint16_t temp = i2c_read_uint16(address, reg); + return (temp / 256) | (temp * 256); +}; + +int16_t i2c_read_int16(uint8_t address, uint8_t reg) { + return (int16_t) i2c_read_uint16(address, reg); +}; + +int16_t i2c_read_int16_le(uint8_t address, uint8_t reg) { + return (int16_t) i2c_read_uint16_le(address, reg); +}; + // ----------------------------------------------------------------------------- // Utils // ----------------------------------------------------------------------------- @@ -194,7 +364,15 @@ void i2cSetup() { Wire.begin(sda, scl); #endif - DEBUG_MSG_P(PSTR("[I2C] Using GPIO%d for SDA and GPIO%d for SCL\n"), sda, scl); + DEBUG_MSG_P(PSTR("[I2C] Using GPIO%u for SDA and GPIO%u for SCL\n"), sda, scl); + + #if I2C_CLEAR_BUS + i2cClearBus(); + #endif + + #if I2C_PERFORM_SCAN + i2cScan(); + #endif } diff --git a/code/espurna/influxdb.ino b/code/espurna/influxdb.ino index c5a795d1..041ce6c6 100644 --- a/code/espurna/influxdb.ino +++ b/code/espurna/influxdb.ino @@ -1,8 +1,8 @@ /* -I2C MODULE +INFLUXDB MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez */ @@ -16,6 +16,10 @@ SyncClient _idb_client; // ----------------------------------------------------------------------------- +bool _idbWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "idb", 3) == 0); +} + void _idbWebSocketOnSend(JsonObject& root) { root["idbVisible"] = 1; root["idbEnabled"] = getSetting("idbEnabled", INFLUXDB_ENABLED).toInt() == 1; @@ -36,50 +40,59 @@ void _idbConfigure() { // ----------------------------------------------------------------------------- -template bool idbSend(const char * topic, T payload) { +bool idbSend(const char * topic, const char * payload) { if (!_idb_enabled) return true; if (!wifiConnected() || (WiFi.getMode() != WIFI_STA)) return true; - char host[64]; - getSetting("idbHost", INFLUXDB_HOST).toCharArray(host, sizeof(host)); - int port = getSetting("idbPort", INFLUXDB_PORT).toInt(); + String h = getSetting("idbHost", INFLUXDB_HOST); + #if MDNS_CLIENT_SUPPORT + h = mdnsResolve(h); + #endif + char * host = strdup(h.c_str()); + unsigned int port = getSetting("idbPort", INFLUXDB_PORT).toInt(); + DEBUG_MSG("[INFLUXDB] Sending to %s:%u\n", host, port); + + bool success = false; - DEBUG_MSG("[INFLUXDB] Sending to %s:%d\n", host, port); _idb_client.setTimeout(2); - if (!_idb_client.connect(host, port)) { + if (_idb_client.connect((const char *) host, port)) { + + char data[128]; + snprintf(data, sizeof(data), "%s,device=%s value=%s", topic, getSetting("hostname").c_str(), String(payload).c_str()); + DEBUG_MSG("[INFLUXDB] Data: %s\n", data); + + char request[256]; + snprintf(request, sizeof(request), "POST /write?db=%s&u=%s&p=%s HTTP/1.1\r\nHost: %s:%u\r\nContent-Length: %d\r\n\r\n%s", + getSetting("idbDatabase", INFLUXDB_DATABASE).c_str(), + getSetting("idbUsername", INFLUXDB_USERNAME).c_str(), getSetting("idbPassword", INFLUXDB_PASSWORD).c_str(), + host, port, strlen(data), data); + + if (_idb_client.printf(request) > 0) { + while (_idb_client.connected() && _idb_client.available() == 0) delay(1); + while (_idb_client.available()) _idb_client.read(); + if (_idb_client.connected()) _idb_client.stop(); + success = true; + } else { + DEBUG_MSG("[INFLUXDB] Sent failed\n"); + } + + _idb_client.stop(); + while (_idb_client.connected()) yield(); + + } else { DEBUG_MSG("[INFLUXDB] Connection failed\n"); - return false; - } - - char data[128]; - snprintf(data, sizeof(data), "%s,device=%s value=%s", topic, getSetting("hostname").c_str(), String(payload).c_str()); - DEBUG_MSG("[INFLUXDB] Data: %s\n", data); - - char request[256]; - snprintf(request, sizeof(request), "POST /write?db=%s&u=%s&p=%s HTTP/1.1\r\nHost: %s:%d\r\nContent-Length: %d\r\n\r\n%s", - getSetting("idbDatabase", INFLUXDB_DATABASE).c_str(), - getSetting("idbUsername", INFLUXDB_USERNAME).c_str(), getSetting("idbPassword", INFLUXDB_PASSWORD).c_str(), - host, port, strlen(data), data); - - if (_idb_client.printf(request) > 0) { - while (_idb_client.connected() && _idb_client.available() == 0) delay(1); - while (_idb_client.available()) _idb_client.read(); - if (_idb_client.connected()) _idb_client.stop(); - return true; } - _idb_client.stop(); - DEBUG_MSG("[INFLUXDB] Sent failed\n"); - while (_idb_client.connected()) delay(0); - return false; + free(host); + return success; } -template bool idbSend(const char * topic, unsigned char id, T payload) { +bool idbSend(const char * topic, unsigned char id, const char * payload) { char measurement[64]; - snprintf_P(measurement, sizeof(measurement), PSTR("%s,id=%d"), topic, id); - return idbSend(topic, payload); + snprintf(measurement, sizeof(measurement), "%s,id=%d", topic, id); + return idbSend(measurement, payload); } bool idbEnabled() { @@ -91,6 +104,7 @@ void idbSetup() { #if WEB_SUPPORT wsOnSendRegister(_idbWebSocketOnSend); wsOnAfterParseRegister(_idbConfigure); + wsOnReceiveRegister(_idbWebSocketOnReceive); #endif } diff --git a/code/espurna/ir.ino b/code/espurna/ir.ino index 2a1e59b0..7dd0a34c 100644 --- a/code/espurna/ir.ino +++ b/code/espurna/ir.ino @@ -2,8 +2,8 @@ IR MODULE -Copyright (C) 2016-2017 by Xose Pérez -Copyright (C) 2017 by François Déchery +Copyright (C) 2016-2018 by Xose Pérez +Copyright (C) 2017-2018 by François Déchery */ @@ -14,6 +14,7 @@ Copyright (C) 2017 by François Déchery IRrecv * _ir_recv; decode_results _ir_results; +unsigned long _ir_last_toggle = 0; // ----------------------------------------------------------------------------- // PRIVATE @@ -43,11 +44,21 @@ void _irProcessCode(unsigned long code) { relayStatus(0, button_value); } + if (button_mode == IR_BUTTON_MODE_TOGGLE) { + + if (millis() - _ir_last_toggle > 250){ + relayToggle(button_value); + _ir_last_toggle = millis(); + } else { + DEBUG_MSG_P(PSTR("[IR] Ignoring repeated code\n")); + } + } + #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE if (button_mode == IR_BUTTON_MODE_BRIGHTER) { lightBrightnessStep(button_value ? 1 : -1); - delay(150); //debounce + nice_delay(150); //debounce } if (button_mode == IR_BUTTON_MODE_RGB) { @@ -92,8 +103,13 @@ void _irProcessCode(unsigned long code) { // ----------------------------------------------------------------------------- void irSetup() { + _ir_recv = new IRrecv(IR_PIN); _ir_recv->enableIRIn(); + + // Register loop + espurnaRegisterLoop(irLoop); + } void irLoop() { diff --git a/code/espurna/led.ino b/code/espurna/led.ino index 0f07a3e1..06fac792 100644 --- a/code/espurna/led.ino +++ b/code/espurna/led.ino @@ -2,7 +2,7 @@ LED MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -30,7 +30,6 @@ bool _ledStatus(unsigned char id) { bool _ledStatus(unsigned char id, bool status) { if (id >=_ledCount()) return false; - bool s = _leds[id].reverse ? !status : status; digitalWrite(_leds[id].pin, _leds[id].reverse ? !status : status); return status; } @@ -59,18 +58,22 @@ void _ledBlink(unsigned char id, unsigned long delayOff, unsigned long delayOn) } #if WEB_SUPPORT + +bool _ledWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "led", 3) == 0); +} + void _ledWebSocketOnSend(JsonObject& root) { if (_ledCount() == 0) return; root["ledVisible"] = 1; root["ledMode0"] = _ledMode(0); } + #endif #if MQTT_SUPPORT void _ledMQTTCallback(unsigned int type, const char * topic, const char * payload) { - static bool isFirstMessage = true; - if (type == MQTT_CONNECT_EVENT) { char buffer[strlen(MQTT_TOPIC_LED) + 3]; snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_LED); @@ -80,7 +83,7 @@ void _ledMQTTCallback(unsigned int type, const char * topic, const char * payloa if (type == MQTT_MESSAGE_EVENT) { // Match topic - String t = mqttSubtopic((char *) topic); + String t = mqttMagnitude((char *) topic); if (!t.startsWith(MQTT_TOPIC_LED)) return; // Get led ID @@ -127,28 +130,28 @@ void ledUpdate(bool value) { void ledSetup() { - #ifdef LED1_PIN + #if LED1_PIN != GPIO_NONE _leds.push_back((led_t) { LED1_PIN, LED1_PIN_INVERSE, LED1_MODE, LED1_RELAY }); #endif - #ifdef LED2_PIN + #if LED2_PIN != GPIO_NONE _leds.push_back((led_t) { LED2_PIN, LED2_PIN_INVERSE, LED2_MODE, LED2_RELAY }); #endif - #ifdef LED3_PIN + #if LED3_PIN != GPIO_NONE _leds.push_back((led_t) { LED3_PIN, LED3_PIN_INVERSE, LED3_MODE, LED3_RELAY }); #endif - #ifdef LED4_PIN + #if LED4_PIN != GPIO_NONE _leds.push_back((led_t) { LED4_PIN, LED4_PIN_INVERSE, LED4_MODE, LED4_RELAY }); #endif - #ifdef LED5_PIN + #if LED5_PIN != GPIO_NONE _leds.push_back((led_t) { LED5_PIN, LED5_PIN_INVERSE, LED5_MODE, LED5_RELAY }); #endif - #ifdef LED6_PIN + #if LED6_PIN != GPIO_NONE _leds.push_back((led_t) { LED6_PIN, LED6_PIN_INVERSE, LED6_MODE, LED6_RELAY }); #endif - #ifdef LED7_PIN + #if LED7_PIN != GPIO_NONE _leds.push_back((led_t) { LED7_PIN, LED7_PIN_INVERSE, LED7_MODE, LED7_RELAY }); #endif - #ifdef LED8_PIN + #if LED8_PIN != GPIO_NONE _leds.push_back((led_t) { LED8_PIN, LED8_PIN_INVERSE, LED8_MODE, LED8_RELAY }); #endif @@ -166,23 +169,52 @@ void ledSetup() { #if WEB_SUPPORT wsOnSendRegister(_ledWebSocketOnSend); wsOnAfterParseRegister(_ledConfigure); + wsOnReceiveRegister(_ledWebSocketOnReceive); #endif DEBUG_MSG_P(PSTR("[LED] Number of leds: %d\n"), _leds.size()); + // Register loop + espurnaRegisterLoop(ledLoop); + + } void ledLoop() { + uint8_t wifi_state = wifiState(); + for (unsigned char i=0; i<_leds.size(); i++) { if (_ledMode(i) == LED_MODE_WIFI) { - if (wifiConnected()) { - if (WiFi.getMode() == WIFI_AP) { + if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) { + _ledBlink(i, 100, 100); + } else if (wifi_state & WIFI_STATE_STA) { + _ledBlink(i, 4900, 100); + } else if (wifi_state & WIFI_STATE_AP) { + _ledBlink(i, 900, 100); + } else { + _ledBlink(i, 500, 500); + } + + } + + if (_ledMode(i) == LED_MODE_FINDME_WIFI) { + + if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) { + _ledBlink(i, 100, 100); + } else if (wifi_state & WIFI_STATE_STA) { + if (relayStatus(_leds[i].relay-1)) { + _ledBlink(i, 4900, 100); + } else { + _ledBlink(i, 100, 4900); + } + } else if (wifi_state & WIFI_STATE_AP) { + if (relayStatus(_leds[i].relay-1)) { _ledBlink(i, 900, 100); } else { - _ledBlink(i, 4900, 100); + _ledBlink(i, 100, 900); } } else { _ledBlink(i, 500, 500); @@ -190,21 +222,21 @@ void ledLoop() { } - if (_ledMode(i) == LED_MODE_MIXED) { + if (_ledMode(i) == LED_MODE_RELAY_WIFI) { - if (wifiConnected()) { + if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) { + _ledBlink(i, 100, 100); + } else if (wifi_state & WIFI_STATE_STA) { if (relayStatus(_leds[i].relay-1)) { - if (WiFi.getMode() == WIFI_AP) { - _ledBlink(i, 900, 100); - } else { - _ledBlink(i, 4900, 100); - } + _ledBlink(i, 100, 4900); } else { - if (WiFi.getMode() == WIFI_AP) { - _ledBlink(i, 100, 900); - } else { - _ledBlink(i, 100, 4900); - } + _ledBlink(i, 4900, 100); + } + } else if (wifi_state & WIFI_STATE_AP) { + if (relayStatus(_leds[i].relay-1)) { + _ledBlink(i, 100, 900); + } else { + _ledBlink(i, 900, 100); } } else { _ledBlink(i, 500, 500); @@ -234,6 +266,17 @@ void ledLoop() { _ledStatus(i, status); } + if (_ledMode(i) == LED_MODE_RELAY) { + bool status = false; + for (unsigned char k=0; k> 16) & 0xff), - (uint16_t)((chipId >> 8) & 0xff), - (uint16_t)chipId & 0xff); - - for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { - m_queue[i].time = 0; - } -} - -void SSDPDeviceClass::update() { - postNotifyUpdate(); -} - -bool SSDPDeviceClass::readLine(String &value) { - char buffer[65]; - int bufferPos = 0; - - while (1) { - int c = m_server->read(); - - if (c < 0) { - buffer[bufferPos] = '\0'; - - break; - } - if (c == '\r' && m_server->peek() == '\n') { - m_server->read(); - - buffer[bufferPos] = '\0'; - - break; - } - if (bufferPos < 64) { - buffer[bufferPos++] = c; - } - } - - value = String(buffer); - - return bufferPos > 0; -} - -bool SSDPDeviceClass::readKeyValue(String &key, String &value) { - char buffer[65]; - int bufferPos = 0; - - while (1) { - int c = m_server->read(); - - if (c < 0) { - if (bufferPos == 0) return false; - - buffer[bufferPos] = '\0'; - - break; - } - if (c == ':') { - buffer[bufferPos] = '\0'; - - while (m_server->peek() == ' ') m_server->read(); - - break; - } - else if (c == '\r' && m_server->peek() == '\n') { - m_server->read(); - - if (bufferPos == 0) return false; - - buffer[bufferPos] = '\0'; - - key = String(); - value = String(buffer); - - return true; - } - if (bufferPos < 64) { - buffer[bufferPos++] = c; - } - } - - key = String(buffer); - - readLine(value); - - return true; -} - -void SSDPDeviceClass::postNotifyALive() { - unsigned long time = millis(); - - post(NOTIFY_ALIVE_INIT, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 10); - post(NOTIFY_ALIVE_INIT, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 55); - post(NOTIFY_ALIVE_INIT, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 80); - - post(NOTIFY_ALIVE_INIT, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 210); - post(NOTIFY_ALIVE_INIT, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 255); - post(NOTIFY_ALIVE_INIT, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 280); - - post(NOTIFY_ALIVE, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 610); - post(NOTIFY_ALIVE, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 655); - post(NOTIFY_ALIVE, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 680); -} - -void SSDPDeviceClass::postNotifyUpdate() { - unsigned long time = millis(); - - post(NOTIFY_UPDATE, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 10); - post(NOTIFY_UPDATE, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 55); - post(NOTIFY_UPDATE, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 80); -} - -void SSDPDeviceClass::postResponse(long mx) { - unsigned long time = millis(); - unsigned long delay = random(0, mx) * 900L; // 1000 ms - 100 ms - - IPAddress address = m_server->remoteIP(); - uint16_t port = m_server->remotePort(); - - post(RESPONSE, ROOT_FOR_ALL, address, port, time + delay / 3); - post(RESPONSE, ROOT_BY_UUID, address, port, time + delay / 3 * 2); - post(RESPONSE, ROOT_BY_TYPE, address, port, time + delay); -} - -void SSDPDeviceClass::postResponse(ssdp_udn_t udn, long mx) { - post(RESPONSE, udn, m_server->remoteIP(), m_server->remotePort(), millis() + random(0, mx) * 900L); // 1000 ms - 100 ms -} - -void SSDPDeviceClass::post(ssdp_message_t type, ssdp_udn_t udn, IPAddress address, uint16_t port, unsigned long time) { - for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { - if (m_queue[i].time == 0) { - m_queue[i].type = type; - m_queue[i].udn = udn; - m_queue[i].address = address; - m_queue[i].port = port; - m_queue[i].time = time; - - break; - } - } -} - -void SSDPDeviceClass::send(ssdp_send_parameters_t *parameters) { - char buffer[1460]; - unsigned int ip = WiFi.localIP(); - - const char *typeTemplate; - const char *uri, *usn1, *usn2, *usn3; - - switch (parameters->type) { - case NOTIFY_ALIVE_INIT: - case NOTIFY_ALIVE: - typeTemplate = SSDP_NOTIFY_ALIVE_TEMPLATE; - break; - case NOTIFY_UPDATE: - typeTemplate = SSDP_NOTIFY_UPDATE_TEMPLATE; - break; - default: // RESPONSE - typeTemplate = SSDP_RESPONSE_TEMPLATE; - break; - } - - String uuid = "uuid:" + String(m_uuid); - - switch (parameters->udn) { - case ROOT_FOR_ALL: - uri = "upnp:rootdevice"; - usn1 = uuid.c_str(); - usn2 = "::"; - usn3 = "upnp:rootdevice"; - break; - case ROOT_BY_UUID: - uri = uuid.c_str(); - usn1 = uuid.c_str(); - usn2 = ""; - usn3 = ""; - break; - case ROOT_BY_TYPE: - uri = m_deviceType; - usn1 = uuid.c_str(); - usn2 = "::"; - usn3 = m_deviceType; - break; - } - - int len = snprintf_P(buffer, sizeof(buffer), - SSDP_PACKET_TEMPLATE, typeTemplate, - SSDP_INTERVAL, m_modelName, m_modelNumber, usn1, usn2, usn3, parameters->type == RESPONSE ? "ST" : "NT", uri, - IP2STR(&ip), m_port, m_schemaURL - ); - - if (parameters->address == SSDP_MULTICAST_ADDR) { - m_server->beginPacketMulticast(parameters->address, parameters->port, m_ttl); - } - else { - m_server->beginPacket(parameters->address, parameters->port); - } - - m_server->write(buffer, len); - m_server->endPacket(); - - parameters->time = parameters->type == NOTIFY_ALIVE ? parameters->time + SSDP_INTERVAL * 900L : 0; // 1000 ms - 100 ms -} - -String SSDPDeviceClass::schema() { - char buffer[1024]; - uint32_t ip = WiFi.localIP(); - snprintf(buffer, sizeof(buffer), SSDP_SCHEMA_TEMPLATE, - IP2STR(&ip), m_port, m_schemaURL, - m_deviceType, - m_friendlyName, - m_presentationURL, - m_serialNumber, - m_modelName, - m_modelNumber, - m_modelURL, - m_manufacturer, - m_manufacturerURL, - m_uuid - ); - return String(buffer); -} - -void SSDPDeviceClass::handleClient() { - IPAddress current = WiFi.localIP(); - - if (m_last != current) { - m_last = current; - - for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { - m_queue[i].time = 0; - } - - if (current != INADDR_NONE) { - if (!m_server) m_server = new WiFiUDP(); - - m_server->beginMulticast(current, SSDP_MULTICAST_ADDR, SSDP_PORT); - - postNotifyALive(); - } - else if (m_server) { - m_server->stop(); - } - } - - if (m_server && m_server->parsePacket()) { - String value; - - if (readLine(value) && value.equalsIgnoreCase("M-SEARCH * HTTP/1.1")) { - String key, st; - bool host = false, man = false; - long mx = 0; - - while (readKeyValue(key, value)) { - if (key.equalsIgnoreCase("HOST") && value.equals("239.255.255.250:1900")) { - host = true; - } - else if (key.equalsIgnoreCase("MAN") && value.equals("\"ssdp:discover\"")) { - man = true; - } - else if (key.equalsIgnoreCase("ST")) { - st = value; - } - else if (key.equalsIgnoreCase("MX")) { - mx = value.toInt(); - } - } - - if (host && man && mx > 0) { - if (st.equals("ssdp:all")) { - postResponse(mx); - } - else if (st.equals("upnp:rootdevice")) { - postResponse(ROOT_FOR_ALL, mx); - } - else if (st.equals("uuid:" + String(m_uuid))) { - postResponse(ROOT_BY_UUID, mx); - } - else if (st.equals(m_deviceType)) { - postResponse(ROOT_BY_TYPE, mx); - } - } - } - - m_server->flush(); - } - else { - unsigned long time = millis(); - - for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { - if (m_queue[i].time > 0 && m_queue[i].time < time) { - send(&m_queue[i]); - } - } - } -} - -void SSDPDeviceClass::setSchemaURL(const char *url) { - strlcpy(m_schemaURL, url, sizeof(m_schemaURL)); -} - -void SSDPDeviceClass::setHTTPPort(uint16_t port) { - m_port = port; -} - -void SSDPDeviceClass::setDeviceType(const char *deviceType) { - strlcpy(m_deviceType, deviceType, sizeof(m_deviceType)); -} - -void SSDPDeviceClass::setName(const char *name) { - strlcpy(m_friendlyName, name, sizeof(m_friendlyName)); -} - -void SSDPDeviceClass::setURL(const char *url) { - strlcpy(m_presentationURL, url, sizeof(m_presentationURL)); -} - -void SSDPDeviceClass::setSerialNumber(const char *serialNumber) { - strlcpy(m_serialNumber, serialNumber, sizeof(m_serialNumber)); -} - -void SSDPDeviceClass::setSerialNumber(const uint32_t serialNumber) { - snprintf(m_serialNumber, sizeof(uint32_t) * 2 + 1, "%08X", serialNumber); -} - -void SSDPDeviceClass::setModelName(const char *name) { - strlcpy(m_modelName, name, sizeof(m_modelName)); -} - -void SSDPDeviceClass::setModelNumber(const char *num) { - strlcpy(m_modelNumber, num, sizeof(m_modelNumber)); -} - -void SSDPDeviceClass::setModelURL(const char *url) { - strlcpy(m_modelURL, url, sizeof(m_modelURL)); -} - -void SSDPDeviceClass::setManufacturer(const char *name) { - strlcpy(m_manufacturer, name, sizeof(m_manufacturer)); -} - -void SSDPDeviceClass::setManufacturerURL(const char *url) { - strlcpy(m_manufacturerURL, url, sizeof(m_manufacturerURL)); -} - -void SSDPDeviceClass::setTTL(const uint8_t ttl) { - m_ttl = ttl; -} - -SSDPDeviceClass SSDPDevice; - -#endif diff --git a/code/espurna/libs/SSDPDevice.h b/code/espurna/libs/SSDPDevice.h deleted file mode 100644 index 0a3bd796..00000000 --- a/code/espurna/libs/SSDPDevice.h +++ /dev/null @@ -1,198 +0,0 @@ -#if SSDP_SUPPORT // SSDP_SUPPORT - -#ifndef _SSDPDEVICE_h -#define _SSDPDEVICE_h - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -#include -#include - -#define SSDP_INTERVAL 1200 -#define SSDP_PORT 1900 -//#define SSDP_METHOD_SIZE 10 -//#define SSDP_URI_SIZE 2 -//#define SSDP_BUFFER_SIZE 64 -#define SSDP_MULTICAST_TTL 2 - -#define SSDP_QUEUE_SIZE 21 - -static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250); - -#define SSDP_UUID_SIZE 37 -#define SSDP_SCHEMA_URL_SIZE 64 -#define SSDP_DEVICE_TYPE_SIZE 64 -#define SSDP_FRIENDLY_NAME_SIZE 64 -#define SSDP_SERIAL_NUMBER_SIZE 32 -#define SSDP_PRESENTATION_URL_SIZE 128 -#define SSDP_MODEL_NAME_SIZE 64 -#define SSDP_MODEL_URL_SIZE 128 -#define SSDP_MODEL_VERSION_SIZE 32 -#define SSDP_MANUFACTURER_SIZE 64 -#define SSDP_MANUFACTURER_URL_SIZE 128 - -static const char* PROGMEM SSDP_RESPONSE_TEMPLATE = - "HTTP/1.1 200 OK\r\n" - "EXT:\r\n"; - -static const char* PROGMEM SSDP_NOTIFY_ALIVE_TEMPLATE = - "NOTIFY * HTTP/1.1\r\n" - "HOST: 239.255.255.250:1900\r\n" - "NTS: ssdp:alive\r\n"; - -static const char* PROGMEM SSDP_NOTIFY_UPDATE_TEMPLATE = - "NOTIFY * HTTP/1.1\r\n" - "HOST: 239.255.255.250:1900\r\n" - "NTS: ssdp:update\r\n"; - -static const char* PROGMEM SSDP_PACKET_TEMPLATE = - "%s" // _ssdp_response_template / _ssdp_notify_template - "CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL - "SERVER: UPNP/1.1 %s/%s\r\n" // m_modelName, m_modelNumber - "USN: %s%s%s\r\n" // m_uuid - "%s: %s\r\n" // "NT" or "ST", m_deviceType - "LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), m_port, m_schemaURL - "\r\n"; - -static const char* PROGMEM SSDP_SCHEMA_TEMPLATE = - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/xml\r\n" - "Connection: close\r\n" - "Access-Control-Allow-Origin: *\r\n" - "\r\n" - "" - "" - "" - "1" - "0" - "" - "http://%u.%u.%u.%u:%u/%s" // WiFi.localIP(), _port - "" - "%s" - "%s" - "%s" - "%s" - "%s" - "%s" - "%s" - "%s" - "%s" - "uuid:%s" - "" -// "" -// "" -// "image/png" -// "48" -// "48" -// "24" -// "icon48.png" -// "" -// "" -// "image/png" -// "120" -// "120" -// "24" -// "icon120.png" -// "" -// "" - "\r\n" - "\r\n"; - -typedef enum { - NOTIFY_ALIVE_INIT, - NOTIFY_ALIVE, - NOTIFY_UPDATE, - RESPONSE -} ssdp_message_t; - -typedef enum { - ROOT_FOR_ALL, - ROOT_BY_UUID, - ROOT_BY_TYPE -} ssdp_udn_t; - -typedef struct { - unsigned long time; - - ssdp_message_t type; - ssdp_udn_t udn; - uint32_t address; - uint16_t port; -} ssdp_send_parameters_t; - -class SSDPDeviceClass { -private: - WiFiUDP *m_server; - - IPAddress m_last; - - char m_schemaURL[SSDP_SCHEMA_URL_SIZE]; - char m_uuid[SSDP_UUID_SIZE]; - char m_deviceType[SSDP_DEVICE_TYPE_SIZE]; - char m_friendlyName[SSDP_FRIENDLY_NAME_SIZE]; - char m_serialNumber[SSDP_SERIAL_NUMBER_SIZE]; - char m_presentationURL[SSDP_PRESENTATION_URL_SIZE]; - char m_manufacturer[SSDP_MANUFACTURER_SIZE]; - char m_manufacturerURL[SSDP_MANUFACTURER_URL_SIZE]; - char m_modelName[SSDP_MODEL_NAME_SIZE]; - char m_modelURL[SSDP_MODEL_URL_SIZE]; - char m_modelNumber[SSDP_MODEL_VERSION_SIZE]; - - uint16_t m_port; - uint8_t m_ttl; - - ssdp_send_parameters_t m_queue[SSDP_QUEUE_SIZE]; -protected: - bool readLine(String &value); - bool readKeyValue(String &key, String &value); - - void postNotifyALive(); - void postNotifyUpdate(); - void postResponse(long mx); - void postResponse(ssdp_udn_t udn, long mx); - void post(ssdp_message_t type, ssdp_udn_t udn, IPAddress address, uint16_t port, unsigned long time); - - void send(ssdp_send_parameters_t *parameters); -public: - SSDPDeviceClass(); - - void update(); - - String schema(); - - void handleClient(); - - void setDeviceType(const String& deviceType) { setDeviceType(deviceType.c_str()); } - void setDeviceType(const char *deviceType); - void setName(const String& name) { setName(name.c_str()); } - void setName(const char *name); - void setURL(const String& url) { setURL(url.c_str()); } - void setURL(const char *url); - void setSchemaURL(const String& url) { setSchemaURL(url.c_str()); } - void setSchemaURL(const char *url); - void setSerialNumber(const String& serialNumber) { setSerialNumber(serialNumber.c_str()); } - void setSerialNumber(const char *serialNumber); - void setSerialNumber(const uint32_t serialNumber); - void setModelName(const String& name) { setModelName(name.c_str()); } - void setModelName(const char *name); - void setModelNumber(const String& num) { setModelNumber(num.c_str()); } - void setModelNumber(const char *num); - void setModelURL(const String& url) { setModelURL(url.c_str()); } - void setModelURL(const char *url); - void setManufacturer(const String& name) { setManufacturer(name.c_str()); } - void setManufacturer(const char *name); - void setManufacturerURL(const String& url) { setManufacturerURL(url.c_str()); } - void setManufacturerURL(const char *url); - void setHTTPPort(uint16_t port); - void setTTL(uint8_t ttl); -}; - -extern SSDPDeviceClass SSDPDevice; - -#endif - -#endif // SSDP_SUPPORT diff --git a/code/espurna/libs/StreamInjector.h b/code/espurna/libs/StreamInjector.h index 24568b6a..03dbd51b 100644 --- a/code/espurna/libs/StreamInjector.h +++ b/code/espurna/libs/StreamInjector.h @@ -1,10 +1,27 @@ -// ----------------------------------------------------------------------------- -// Stream Injector -// ----------------------------------------------------------------------------- +/* + +StreamInjector + +Copyright (C) 2016-2018 by Xose Pérez + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ #pragma once -#define STREAM_INJECTOR_BUFFER_SIZE 32 +#include class StreamInjector : public Stream { @@ -12,32 +29,53 @@ class StreamInjector : public Stream { typedef std::function writeCallback; - StreamInjector(Stream& serial) : _stream(serial) {} + StreamInjector(size_t buflen = 128) : _buffer_size(buflen) { + _buffer = new char[buflen]; + } + + ~StreamInjector() { + delete[] _buffer; + } + + // --------------------------------------------------------------------- + + virtual uint8_t inject(char ch) { + _buffer[_buffer_write] = ch; + _buffer_write = (_buffer_write + 1) % _buffer_size; + return 1; + } + + virtual uint8_t inject(char *data, size_t len) { + for (uint8_t i=0; i _buffer_write) { - bytes += (_buffer_write - _buffer_read + STREAM_INJECTOR_BUFFER_SIZE); + bytes += (_buffer_write - _buffer_read + _buffer_size); } else if (_buffer_read < _buffer_write) { bytes += (_buffer_write - _buffer_read); } @@ -45,34 +83,23 @@ class StreamInjector : public Stream { } virtual int peek() { - int ch = _stream.peek(); - if (ch == -1) { - if (_buffer_read != _buffer_write) { - ch = _buffer[_buffer_read]; - } + int ch = -1; + if (_buffer_read != _buffer_write) { + ch = _buffer[_buffer_read]; } return ch; } virtual void flush() { - _stream.flush(); _buffer_read = _buffer_write; } - virtual void inject(char *data, size_t len) { - for (int i=0; i *_buffer; }; diff --git a/code/espurna/libs/fs_math.c b/code/espurna/libs/fs_math.c new file mode 100644 index 00000000..8f45eb26 --- /dev/null +++ b/code/espurna/libs/fs_math.c @@ -0,0 +1,636 @@ +/** + * This code is available at + * http://www.mindspring.com/~pfilandr/C/fs_math/ + * and it is believed to be public domain. + */ + +/* BEGIN fs_math.c */ + +#include "fs_math.h" + +#include +/* +** pi == (atan(1.0 / 3) + atan(1.0 / 2)) * 4 +*/ +static double fs_pi(void); +static long double fs_pil(void); + +double fs_sqrt(double x) +{ + int n; + double a, b; + + if (x > 0 && DBL_MAX >= x) { + for (n = 0; x > 2; x /= 4) { + ++n; + } + while (0.5 > x) { + --n; + x *= 4; + } + a = x; + b = (1 + x) / 2; + do { + x = b; + b = (a / x + x) / 2; + } while (x > b); + while (n > 0) { + x *= 2; + --n; + } + while (0 > n) { + x /= 2; + ++n; + } + } else { + if (x != 0) { + x = DBL_MAX; + } + } + return x; +} + +double fs_log(double x) +{ + int n; + double a, b, c, epsilon; + static double A, B, C; + static int initialized; + + if (x > 0 && DBL_MAX >= x) { + if (!initialized) { + initialized = 1; + A = fs_sqrt(2); + B = A / 2; + C = fs_log(A); + } + for (n = 0; x > A; x /= 2) { + ++n; + } + while (B > x) { + --n; + x *= 2; + } + a = (x - 1) / (x + 1); + x = C * n + a; + c = a * a; + n = 1; + epsilon = DBL_EPSILON * x; + if (0 > a) { + if (epsilon > 0) { + epsilon = -epsilon; + } + do { + n += 2; + a *= c; + b = a / n; + x += b; + } while (epsilon > b); + } else { + if (0 > epsilon) { + epsilon = -epsilon; + } + do { + n += 2; + a *= c; + b = a / n; + x += b; + } while (b > epsilon); + } + x *= 2; + } else { + x = -DBL_MAX; + } + return x; +} + +double fs_log10(double x) +{ + static double log_10; + static int initialized; + + if (!initialized) { + initialized = 1; + log_10 = fs_log(10); + } + return x > 0 && DBL_MAX >= x ? fs_log(x) / log_10 : fs_log(x); +} + +double fs_exp(double x) +{ + unsigned n, square; + double b, e; + static double x_max, x_min, epsilon; + static int initialized; + + if (!initialized) { + initialized = 1; + x_max = fs_log(DBL_MAX); + x_min = fs_log(DBL_MIN); + epsilon = DBL_EPSILON / 4; + } + if (x_max >= x && x >= x_min) { + for (square = 0; x > 1; x /= 2) { + ++square; + } + while (-1 > x) { + ++square; + x /= 2; + } + e = b = n = 1; + do { + b /= n++; + b *= x; + e += b; + b /= n++; + b *= x; + e += b; + } while (b > epsilon); + while (square-- != 0) { + e *= e; + } + } else { + e = x > 0 ? DBL_MAX : 0; + } + return e; +} + +double fs_modf(double value, double *iptr) +{ + double a, b; + const double c = value; + + if (0 > c) { + value = -value; + } + if (DBL_MAX >= value) { + for (*iptr = 0; value >= 1; value -= b) { + a = value / 2; + b = 1; + while (a >= b) { + b *= 2; + } + *iptr += b; + } + } else { + *iptr = value; + value = 0; + } + if (0 > c) { + *iptr = -*iptr; + value = -value; + } + return value; +} + +double fs_fmod(double x, double y) +{ + double a, b; + const double c = x; + + if (0 > c) { + x = -x; + } + if (0 > y) { + y = -y; + } + if (y != 0 && DBL_MAX >= y && DBL_MAX >= x) { + while (x >= y) { + a = x / 2; + b = y; + while (a >= b) { + b *= 2; + } + x -= b; + } + } else { + x = 0; + } + return 0 > c ? -x : x; +} + +double fs_pow(double x, double y) +{ + double p = 0; + + if (0 > x && fs_fmod(y, 1) == 0) { + if (fs_fmod(y, 2) == 0) { + p = fs_exp(fs_log(-x) * y); + } else { + p = -fs_exp(fs_log(-x) * y); + } + } else { + if (x != 0 || 0 >= y) { + p = fs_exp(fs_log( x) * y); + } + } + return p; +} + +static double fs_pi(void) +{ + unsigned n; + double a, b, epsilon; + static double p; + static int initialized; + + if (!initialized) { + initialized = 1; + epsilon = DBL_EPSILON / 4; + n = 1; + a = 3; + do { + a /= 9; + b = a / n; + n += 2; + a /= 9; + b -= a / n; + n += 2; + p += b; + } while (b > epsilon); + epsilon = DBL_EPSILON / 2; + n = 1; + a = 2; + do { + a /= 4; + b = a / n; + n += 2; + a /= 4; + b -= a / n; + n += 2; + p += b; + } while (b > epsilon); + p *= 4; + } + return p; +} + +double fs_cos(double x) +{ + unsigned n; + int negative, sine; + double a, b, c; + static double pi, two_pi, half_pi, third_pi, epsilon; + static int initialized; + + if (0 > x) { + x = -x; + } + if (DBL_MAX >= x) { + if (!initialized) { + initialized = 1; + pi = fs_pi(); + two_pi = 2 * pi; + half_pi = pi / 2; + third_pi = pi / 3; + epsilon = DBL_EPSILON / 2; + } + if (x > two_pi) { + x = fs_fmod(x, two_pi); + } + if (x > pi) { + x = two_pi - x; + } + if (x > half_pi) { + x = pi - x; + negative = 1; + } else { + negative = 0; + } + if (x > third_pi) { + x = half_pi - x; + sine = 1; + } else { + sine = 0; + } + c = x * x; + x = n = 0; + a = 1; + do { + b = a; + a *= c; + a /= ++n; + a /= ++n; + b -= a; + a *= c; + a /= ++n; + a /= ++n; + x += b; + } while (b > epsilon); + if (sine) { + x = fs_sqrt((1 - x) * (1 + x)); + } + if (negative) { + x = -x; + } + } else { + x = -DBL_MAX; + } + return x; +} + +double fs_log2(double x) +{ + static double log_2; + static int initialized; + + if (!initialized) { + initialized = 1; + log_2 = fs_log(2); + } + return x > 0 && DBL_MAX >= x ? fs_log(x) / log_2 : fs_log(x); +} + +double fs_exp2(double x) +{ + static double log_2; + static int initialized; + + if (!initialized) { + initialized = 1; + log_2 = fs_log(2); + } + return fs_exp(x * log_2); +} + +long double fs_powl(long double x, long double y) +{ + long double p; + + if (0 > x && fs_fmodl(y, 1) == 0) { + if (fs_fmodl(y, 2) == 0) { + p = fs_expl(fs_logl(-x) * y); + } else { + p = -fs_expl(fs_logl(-x) * y); + } + } else { + if (x != 0 || 0 >= y) { + p = fs_expl(fs_logl( x) * y); + } else { + p = 0; + } + } + return p; +} + +long double fs_sqrtl(long double x) +{ + long int n; + long double a, b; + + if (x > 0 && LDBL_MAX >= x) { + for (n = 0; x > 2; x /= 4) { + ++n; + } + while (0.5 > x) { + --n; + x *= 4; + } + a = x; + b = (1 + x) / 2; + do { + x = b; + b = (a / x + x) / 2; + } while (x > b); + while (n > 0) { + x *= 2; + --n; + } + while (0 > n) { + x /= 2; + ++n; + } + } else { + if (x != 0) { + x = LDBL_MAX; + } + } + return x; +} + +long double fs_logl(long double x) +{ + long int n; + long double a, b, c, epsilon; + static long double A, B, C; + static int initialized; + + if (x > 0 && LDBL_MAX >= x) { + if (!initialized) { + initialized = 1; + B = 1.5; + do { + A = B; + B = 1 / A + A / 2; + } while (A > B); + B /= 2; + C = fs_logl(A); + } + for (n = 0; x > A; x /= 2) { + ++n; + } + while (B > x) { + --n; + x *= 2; + } + a = (x - 1) / (x + 1); + x = C * n + a; + c = a * a; + n = 1; + epsilon = LDBL_EPSILON * x; + if (0 > a) { + if (epsilon > 0) { + epsilon = -epsilon; + } + do { + n += 2; + a *= c; + b = a / n; + x += b; + } while (epsilon > b); + } else { + if (0 > epsilon) { + epsilon = -epsilon; + } + do { + n += 2; + a *= c; + b = a / n; + x += b; + } while (b > epsilon); + } + x *= 2; + } else { + x = -LDBL_MAX; + } + return x; +} + +long double fs_expl(long double x) +{ + long unsigned n, square; + long double b, e; + static long double x_max, x_min, epsilon; + static int initialized; + + if (!initialized) { + initialized = 1; + x_max = fs_logl(LDBL_MAX); + x_min = fs_logl(LDBL_MIN); + epsilon = LDBL_EPSILON / 4; + } + if (x_max >= x && x >= x_min) { + for (square = 0; x > 1; x /= 2) { + ++square; + } + while (-1 > x) { + ++square; + x /= 2; + } + e = b = n = 1; + do { + b /= n++; + b *= x; + e += b; + b /= n++; + b *= x; + e += b; + } while (b > epsilon); + while (square-- != 0) { + e *= e; + } + } else { + e = x > 0 ? LDBL_MAX : 0; + } + return e; +} + +static long double fs_pil(void) +{ + long unsigned n; + long double a, b, epsilon; + static long double p; + static int initialized; + + if (!initialized) { + initialized = 1; + epsilon = LDBL_EPSILON / 4; + n = 1; + a = 3; + do { + a /= 9; + b = a / n; + n += 2; + a /= 9; + b -= a / n; + n += 2; + p += b; + } while (b > epsilon); + epsilon = LDBL_EPSILON / 2; + n = 1; + a = 2; + do { + a /= 4; + b = a / n; + n += 2; + a /= 4; + b -= a / n; + n += 2; + p += b; + } while (b > epsilon); + p *= 4; + } + return p; +} + +long double fs_cosl(long double x) +{ + long unsigned n; + int negative, sine; + long double a, b, c; + static long double pi, two_pi, half_pi, third_pi, epsilon; + static int initialized; + + if (0 > x) { + x = -x; + } + if (LDBL_MAX >= x) { + if (!initialized) { + initialized = 1; + pi = fs_pil(); + two_pi = 2 * pi; + half_pi = pi / 2; + third_pi = pi / 3; + epsilon = LDBL_EPSILON / 2; + } + if (x > two_pi) { + x = fs_fmodl(x, two_pi); + } + if (x > pi) { + x = two_pi - x; + } + if (x > half_pi) { + x = pi - x; + negative = 1; + } else { + negative = 0; + } + if (x > third_pi) { + x = half_pi - x; + sine = 1; + } else { + sine = 0; + } + c = x * x; + x = n = 0; + a = 1; + do { + b = a; + a *= c; + a /= ++n; + a /= ++n; + b -= a; + a *= c; + a /= ++n; + a /= ++n; + x += b; + } while (b > epsilon); + if (sine) { + x = fs_sqrtl((1 - x) * (1 + x)); + } + if (negative) { + x = -x; + } + } else { + x = -LDBL_MAX; + } + return x; +} + +long double fs_fmodl(long double x, long double y) +{ + long double a, b; + const long double c = x; + + if (0 > c) { + x = -x; + } + if (0 > y) { + y = -y; + } + if (y != 0 && LDBL_MAX >= y && LDBL_MAX >= x) { + while (x >= y) { + a = x / 2; + b = y; + while (a >= b) { + b *= 2; + } + x -= b; + } + } else { + x = 0; + } + return 0 > c ? -x : x; +} + +/* END fs_math.c */ diff --git a/code/espurna/libs/fs_math.h b/code/espurna/libs/fs_math.h new file mode 100644 index 00000000..1884fcdd --- /dev/null +++ b/code/espurna/libs/fs_math.h @@ -0,0 +1,116 @@ +/** + * This code is available at + * http://www.mindspring.com/~pfilandr/C/fs_math/ + * and it is believed to be public domain. + */ + +/* BEGIN fs_math.h */ +/* +** Portable freestanding code. +*/ +#ifndef H_FS_MATH_H +#define H_FS_MATH_H + +double fs_sqrt(double x); +double fs_log(double x); +double fs_log10(double x); +/* +** exp(x) = 1 + x + x^2/2! + x^3/3! + ... +*/ +double fs_exp(double x); +double fs_modf(double value, double *iptr); +double fs_fmod(double x, double y); +double fs_pow(double x, double y); +double fs_cos(double x); +/* +** C99 +*/ +double fs_log2(double x); +double fs_exp2(double x); +long double fs_powl(long double x, long double y); +long double fs_sqrtl(long double x); +long double fs_logl(long double x); +long double fs_expl(long double x); +long double fs_cosl(long double x); +long double fs_fmodl(long double x, long double y); + +#endif + +/* END fs_math.h */ + +#if 0 + +/* +> > Anybody know where I can get some source code for a +> > reasonably fast double +> > precision square root algorithm in C. +> > I'm looking for one that is not IEEE +> > compliant as I am running on a Z/OS mainframe. +> > +> > I would love to use the standard library but +> > unfortunatly I'm using a +> > stripped down version of C that looses the the runtime library +> > (we have to write our own). +> +> long double Ssqrt(long double x) +> { +> long double a, b; +> size_t c; + +size_t is a bug here. +c needs to be a signed type: + long c; + +> if (x > 0) { +> c = 0; +> while (x > 4) { +> x /= 4; +> ++c; +> } +> while (1.0 / 4 > x) { +> x *= 4; +> --c; +> } +> a = x; +> b = ((4 > a) + a) / 2; + +Not a bug, but should be: + b = (1 + a) / 2; + +> do { +> x = b; +> b = (a / x + x) / 2; +> } while (x > b); +> if (c > 0) { + +The above line is why c needs to be a signed type, +otherwise the decremented values of c, are greater than zero, +and the function won't work if the initial value of x +is less than 0.25 + +> while (c--) { +> x *= 2; +> } +> } else { +> while (c++) { +> x /= 2; +> } +> } +> } +> return x; +> } + +> +> > +> > That algorithm was actually 4 times slower +> > then the one below, and more +> > code. It was accurate though. +> > +> +> Sorry Pete, I wasn't looking very carefully. +> When I converted your function +> to double precision it's was much quicker, the best I've seen yet. + +*/ + +#endif diff --git a/code/espurna/pwm.c b/code/espurna/libs/pwm.c similarity index 99% rename from code/espurna/pwm.c rename to code/espurna/libs/pwm.c index 9a316bb8..0e3794c1 100644 --- a/code/espurna/pwm.c +++ b/code/espurna/libs/pwm.c @@ -209,7 +209,6 @@ _pwm_phases_prep(struct pwm_phase* pwm) { uint8_t n, phases; - uint16_t off_mask = 0; for (n = 0; n < pwm_channels + 2; n++) { pwm[n].ticks = 0; pwm[n].on_mask = 0; diff --git a/code/espurna/libs/pwm.h b/code/espurna/libs/pwm.h index 1f26a1af..bf5605fb 100755 --- a/code/espurna/libs/pwm.h +++ b/code/espurna/libs/pwm.h @@ -9,7 +9,7 @@ /*NOTE!! : DO NOT CHANGE THIS FILE*/ /*SUPPORT UP TO 8 PWM CHANNEL*/ -#define PWM_CHANNEL_NUM_MAX 8 +//#define PWM_CHANNEL_NUM_MAX 8 struct pwm_param { uint32 period; diff --git a/code/espurna/light.ino b/code/espurna/light.ino index eb2363ef..ef2b915f 100644 --- a/code/espurna/light.ino +++ b/code/espurna/light.ino @@ -2,7 +2,7 @@ LIGHT MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -12,7 +12,12 @@ Copyright (C) 2016-2017 by Xose Pérez #include #include +extern "C" { + #include "libs/fs_math.h" +} + #if LIGHT_PROVIDER == LIGHT_PROVIDER_DIMMER +#define PWM_CHANNEL_NUM_MAX LIGHT_CHANNELS extern "C" { #include "libs/pwm.h" } @@ -26,7 +31,9 @@ Ticker _light_transition_ticker; typedef struct { unsigned char pin; bool reverse; - unsigned char value; // target or nominal value + bool state; + unsigned char inputValue; // value that has been inputted + unsigned char value; // normalized value including brightness unsigned char shadow; // represented value double current; // transition value } channel_t; @@ -34,11 +41,14 @@ std::vector _light_channel; bool _light_state = false; bool _light_use_transitions = false; +unsigned int _light_transition_time = LIGHT_TRANSITION_TIME; bool _light_has_color = false; bool _light_use_white = false; +bool _light_use_cct = false; bool _light_use_gamma = false; unsigned long _light_steps_left = 1; -unsigned int _light_brightness = LIGHT_MAX_BRIGHTNESS; +unsigned char _light_brightness = LIGHT_MAX_BRIGHTNESS; +unsigned int _light_mireds = round((LIGHT_COLDWHITE_MIRED+LIGHT_WARMWHITE_MIRED)/2); #if LIGHT_PROVIDER == LIGHT_PROVIDER_MY92XX #include @@ -83,99 +93,138 @@ const unsigned char _light_gamma_table[] = { // UTILS // ----------------------------------------------------------------------------- -void _fromLong(unsigned long value, bool brightness) { +void _setRGBInputValue(unsigned char red, unsigned char green, unsigned char blue) { + _light_channel[0].inputValue = constrain(red, 0, LIGHT_MAX_VALUE); + _light_channel[1].inputValue = constrain(green, 0, LIGHT_MAX_VALUE);; + _light_channel[2].inputValue = constrain(blue, 0, LIGHT_MAX_VALUE);; +} - if (brightness) { - _light_channel[0].value = (value >> 24) & 0xFF; - _light_channel[1].value = (value >> 16) & 0xFF; - _light_channel[2].value = (value >> 8) & 0xFF; - _light_brightness = (value & 0xFF) * LIGHT_MAX_BRIGHTNESS / 255; - } else { - _light_channel[0].value = (value >> 16) & 0xFF; - _light_channel[1].value = (value >> 8) & 0xFF; - _light_channel[2].value = (value) & 0xFF; - } +void _generateBrightness() { -} + double brightness = (double) _light_brightness / LIGHT_MAX_BRIGHTNESS; -void _fromRGB(const char * rgb) { + // Convert RGB to RGBW(W) + if (_light_has_color && _light_use_white) { - char * p = (char *) rgb; - if (strlen(p) == 0) return; + // Substract the common part from RGB channels and add it to white channel. So [250,150,50] -> [200,100,0,50] + unsigned char white = std::min(_light_channel[0].inputValue, std::min(_light_channel[1].inputValue, _light_channel[2].inputValue)); + for (unsigned int i=0; i < 3; i++) { + _light_channel[i].value = _light_channel[i].inputValue - white; + } - // if color begins with a # then assume HEX RGB - if (p[0] == '#') { + // Split the White Value across 2 White LED Strips. + if (_light_use_cct) { - if (_light_has_color) { + // This change the range from 153-500 to 0-347 so we get a value between 0 and 1 in the end. + double miredFactor = ((double) _light_mireds - (double) LIGHT_COLDWHITE_MIRED)/((double) LIGHT_WARMWHITE_MIRED - (double) LIGHT_COLDWHITE_MIRED); - ++p; - unsigned long value = strtoul(p, NULL, 16); + // set cold white + _light_channel[3].inputValue = 0; + _light_channel[3].value = round(((double) 1.0 - miredFactor) * white); - // RGBA values are interpreted like RGB + brightness - _fromLong(value, strlen(p) > 7); + // set warm white + _light_channel[4].inputValue = 0; + _light_channel[4].value = round(miredFactor * white); + } else { + _light_channel[3].inputValue = 0; + _light_channel[3].value = white; + } + + // Scale up to equal input values. So [250,150,50] -> [200,100,0,50] -> [250, 125, 0, 63] + unsigned char max_in = std::max(_light_channel[0].inputValue, std::max(_light_channel[1].inputValue, _light_channel[2].inputValue)); + unsigned char max_out = std::max(std::max(_light_channel[0].value, _light_channel[1].value), std::max(_light_channel[2].value, _light_channel[3].value)); + unsigned char channelSize = _light_use_cct ? 5 : 4; + if (_light_use_cct) { + max_out = std::max(max_out, _light_channel[4].value); } - // it's a temperature in mireds - } else if (p[0] == 'M') { + double factor = (max_out > 0) ? (double) (max_in / max_out) : 0; + for (unsigned char i=0; i < channelSize; i++) { + _light_channel[i].value = round((double) _light_channel[i].value * factor * brightness); + } - if (_light_has_color) { - unsigned long mireds = atol(p + 1); - _fromMireds(mireds); + // Scale white channel to match brightness + for (unsigned char i=3; i < channelSize; i++) { + _light_channel[i].value = constrain(_light_channel[i].value * LIGHT_WHITE_FACTOR, 0, LIGHT_MAX_BRIGHTNESS); } - // it's a temperature in kelvin - } else if (p[0] == 'K') { + // For the rest of channels, don't apply brightness, it is already in the inputValue + // i should be 4 when RGBW and 5 when RGBWW + for (unsigned char i=channelSize; i < _light_channel.size(); i++) { + _light_channel[i].value = _light_channel[i].inputValue; + } - if (_light_has_color) { - unsigned long kelvin = atol(p + 1); - _fromKelvin(kelvin); + } else { + + // Don't apply brightness, it is already in the target: + for (unsigned char i=0; i < _light_channel.size(); i++) { + if (_light_has_color & (i<3)) { + _light_channel[i].value = _light_channel[i].inputValue * brightness; + } else { + _light_channel[i].value = _light_channel[i].inputValue; + } } - // otherwise assume decimal values separated by commas + } + +} + +// ----------------------------------------------------------------------------- +// Input Values +// ----------------------------------------------------------------------------- + +void _fromLong(unsigned long value, bool brightness) { + if (brightness) { + _setRGBInputValue((value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF); + _light_brightness = (value & 0xFF) * LIGHT_MAX_BRIGHTNESS / 255; } else { + _setRGBInputValue((value >> 16) & 0xFF, (value >> 8) & 0xFF, (value) & 0xFF); + } +} + +void _fromRGB(const char * rgb) { + char * p = (char *) rgb; + if (strlen(p) == 0) return; + switch (p[0]) { + case '#': // HEX Value + if (_light_has_color) { + ++p; + unsigned long value = strtoul(p, NULL, 16); + // RGBA values are interpreted like RGB + brightness + _fromLong(value, strlen(p) > 7); + } + break; + case 'M': // Mired Value + _fromMireds(atol(p + 1)); + break; + case 'K': // Kelvin Value + _fromKelvin(atol(p + 1)); + break; + default: // assume decimal values separated by commas char * tok; unsigned char count = 0; unsigned char channels = _light_channel.size(); tok = strtok(p, ","); while (tok != NULL) { - _light_channel[count].value = atoi(tok); + _light_channel[count].inputValue = atoi(tok); if (++count == channels) break; tok = strtok(NULL, ","); } - // RGB but less than 3 values received + // RGB but less than 3 values received, assume it is 0 if (_light_has_color && (count < 3)) { - _light_channel[1].value = _light_channel[0].value; - _light_channel[2].value = _light_channel[0].value; + // check channel 1 and 2: + for (int i = 1; i <= 2; i++) { + if (count < (i+1)) { + _light_channel[i].inputValue = 0; + } + } } - + break; } - -} - -void _toRGB(char * rgb, size_t len, bool applyBrightness) { - - if (!_light_has_color) return; - - float b = applyBrightness ? (float) _light_brightness / LIGHT_MAX_BRIGHTNESS : 1; - - unsigned long value = 0; - - value += _light_channel[0].value * b; - value <<= 8; - value += _light_channel[1].value * b; - value <<= 8; - value += _light_channel[2].value * b; - - snprintf_P(rgb, len, PSTR("#%06X"), value); - -} - -void _toRGB(char * rgb, size_t len) { - _toRGB(rgb, len, false); } // HSV string is expected to be "H,S,V", where: @@ -202,86 +251,116 @@ void _fromHSV(const char * hsv) { // HSV to RGB transformation ----------------------------------------------- + //INPUT: [0,100,57] + //IS: [145,0,0] + //SHOULD: [255,0,0] + double h = (value[0] == 360) ? 0 : (double) value[0] / 60.0; double f = (h - floor(h)); double s = (double) value[1] / 100.0; - unsigned char v = round((double) value[2] * 255.0 / 100.0); - unsigned char p = round(v * (1.0 - s)); - unsigned char q = round(v * (1.0 - s * f)); - unsigned char t = round(v * (1.0 - s * (1.0 - f))); + + _light_brightness = round((double) value[2] * 2.55); // (255/100) + unsigned char p = round(255 * (1.0 - s)); + unsigned char q = round(255 * (1.0 - s * f)); + unsigned char t = round(255 * (1.0 - s * (1.0 - f))); switch (int(h)) { case 0: - _light_channel[0].value = v; - _light_channel[1].value = t; - _light_channel[2].value = p; + _setRGBInputValue(255, t, p); break; case 1: - _light_channel[0].value = q; - _light_channel[1].value = v; - _light_channel[2].value = p; + _setRGBInputValue(q, 255, p); break; case 2: - _light_channel[0].value = p; - _light_channel[1].value = v; - _light_channel[2].value = t; + _setRGBInputValue(p, 255, t); break; case 3: - _light_channel[0].value = p; - _light_channel[1].value = q; - _light_channel[2].value = v; + _setRGBInputValue(p, q, 255); break; case 4: - _light_channel[0].value = t; - _light_channel[1].value = p; - _light_channel[2].value = v; + _setRGBInputValue(t, p, 255); break; case 5: - _light_channel[0].value = v; - _light_channel[1].value = p; - _light_channel[2].value = q; + _setRGBInputValue(255, p, q); break; default: - _light_channel[0].value = 0; - _light_channel[1].value = 0; - _light_channel[2].value = 0; + _setRGBInputValue(0, 0, 0); break; } +} + +// Thanks to Sacha Telgenhof for sharing this code in his AiLight library +// https://github.com/stelgenhof/AiLight +void _fromKelvin(unsigned long kelvin) { - _light_brightness = LIGHT_MAX_BRIGHTNESS; + if (!_light_has_color) return; + + if (_light_use_cct) { + _setRGBInputValue(LIGHT_MAX_VALUE, LIGHT_MAX_VALUE, LIGHT_MAX_VALUE); + return; + } + + _light_mireds = constrain(round(1000000UL / kelvin), LIGHT_MIN_MIREDS, LIGHT_MAX_MIREDS); + + // Calculate colors + kelvin /= 100; + unsigned int red = (kelvin <= 66) + ? LIGHT_MAX_VALUE + : 329.698727446 * fs_pow((double) (kelvin - 60), -0.1332047592); + unsigned int green = (kelvin <= 66) + ? 99.4708025861 * fs_log(kelvin) - 161.1195681661 + : 288.1221695283 * fs_pow((double) kelvin, -0.0755148492); + unsigned int blue = (kelvin >= 66) + ? LIGHT_MAX_VALUE + : ((kelvin <= 19) + ? 0 + : 138.5177312231 * fs_log(kelvin - 10) - 305.0447927307); + + _setRGBInputValue(red, green, blue); } -void _toHSV(char * hsv, size_t len) { +// Color temperature is measured in mireds (kelvin = 1e6/mired) +void _fromMireds(unsigned long mireds) { + unsigned long kelvin = constrain(1000000UL / mireds, 1000, 40000); + _fromKelvin(kelvin); +} - if (!_light_has_color) return; +// ----------------------------------------------------------------------------- +// Output Values +// ----------------------------------------------------------------------------- + +void _toRGB(char * rgb, size_t len) { + unsigned long value = 0; + + value += _light_channel[0].inputValue; + value <<= 8; + value += _light_channel[1].inputValue; + value <<= 8; + value += _light_channel[2].inputValue; + + snprintf_P(rgb, len, PSTR("#%06X"), value); +} - double min, max; +void _toHSV(char * hsv, size_t len) { double h, s, v; + double brightness = (double) _light_brightness / LIGHT_MAX_BRIGHTNESS; - double r = (double) _light_channel[0].value / 255.0; - double g = (double) _light_channel[1].value / 255.0; - double b = (double) _light_channel[2].value / 255.0; + double r = (double) (_light_channel[0].inputValue * brightness) / 255.0; + double g = (double) (_light_channel[1].inputValue * brightness) / 255.0; + double b = (double) (_light_channel[2].inputValue * brightness) / 255.0; - min = (r < g) ? r : g; - min = (min < b) ? min : b; - max = (r > g) ? r : g; - max = (max > b) ? max : b; + double min = std::min(r, std::min(g, b)); + double max = std::max(r, std::max(g, b)); v = 100.0 * max; if (v == 0) { - h = s = 0; - } else { - s = 100.0 * (max - min) / max; if (s == 0) { - h = 0; - } else { - if (max == r) { if (g >= b) { h = 0.0 + 60.0 * (g - b) / (max - min); @@ -294,64 +373,31 @@ void _toHSV(char * hsv, size_t len) { h = 240.0 + 60.0 * (r - g) / (max - min); } } - } // String snprintf_P(hsv, len, PSTR("%d,%d,%d"), round(h), round(s), round(v)); - } -void _toLong(char * color, size_t len, bool applyBrightness) { - +void _toLong(char * color, size_t len) { if (!_light_has_color) return; - float b = applyBrightness ? (float) _light_brightness / LIGHT_MAX_BRIGHTNESS : 1; - snprintf_P(color, len, PSTR("%d,%d,%d"), - (int) (_light_channel[0].value * b), - (int) (_light_channel[1].value * b), - (int) (_light_channel[2].value * b) + (int) _light_channel[0].inputValue, + (int) _light_channel[1].inputValue, + (int) _light_channel[2].inputValue ); - -} - -void _toLong(char * color, size_t len) { - _toLong(color, len, false); -} - -// Thanks to Sacha Telgenhof for sharing this code in his AiLight library -// https://github.com/stelgenhof/AiLight -void _fromKelvin(unsigned long kelvin) { - - // Check we have RGB channels - if (!_light_has_color) return; - - // Calculate colors - unsigned int red = (kelvin <= 66) - ? LIGHT_MAX_VALUE - : 329.698727446 * pow((kelvin - 60), -0.1332047592); - unsigned int green = (kelvin <= 66) - ? 99.4708025861 * log(kelvin) - 161.1195681661 - : 288.1221695283 * pow(kelvin, -0.0755148492); - unsigned int blue = (kelvin >= 66) - ? LIGHT_MAX_VALUE - : ((kelvin <= 19) - ? 0 - : 138.5177312231 * log(kelvin - 10) - 305.0447927307); - - // Save values - _light_channel[0].value = constrain(red, 0, LIGHT_MAX_VALUE); - _light_channel[1].value = constrain(green, 0, LIGHT_MAX_VALUE); - _light_channel[2].value = constrain(blue, 0, LIGHT_MAX_VALUE); - } -// Color temperature is measured in mireds (kelvin = 1e6/mired) -void _fromMireds(unsigned long mireds) { - if (mireds == 0) mireds = 1; - unsigned long kelvin = constrain(1000000UL / mireds, 1000, 40000) / 100; - _fromKelvin(kelvin); +void _toCSV(char * buffer, size_t len, bool applyBrightness) { + char num[10]; + float b = applyBrightness ? (float) _light_brightness / LIGHT_MAX_BRIGHTNESS : 1; + for (unsigned char i=0; i<_light_channel.size(); i++) { + itoa(_light_channel[i].inputValue * b, num, 10); + if (i>0) strncat(buffer, ",", len--); + strncat(buffer, num, len); + len = len - strlen(num); + } } // ----------------------------------------------------------------------------- @@ -381,31 +427,18 @@ void _shadow() { // Transitions unsigned char target; for (unsigned int i=0; i < _light_channel.size(); i++) { - if (_light_state) { - target = _light_channel[i].value; - if ((_light_brightness < LIGHT_MAX_BRIGHTNESS) && _light_has_color && (i < 3)) { - target *= ((float) _light_brightness / LIGHT_MAX_BRIGHTNESS); - } - } else { - target = 0; - } + + target = _light_state && _light_channel[i].state ? _light_channel[i].value : 0; + if (_light_steps_left == 0) { _light_channel[i].current = target; } else { double difference = (double) (target - _light_channel[i].current) / (_light_steps_left + 1); _light_channel[i].current = _light_channel[i].current + difference; } + _light_channel[i].shadow = _light_channel[i].current; - } - // Use white channel for same RGB - if (_light_use_white && _light_has_color) { - if (_light_channel[0].shadow == _light_channel[1].shadow && _light_channel[1].shadow == _light_channel[2].shadow ) { - _light_channel[3].shadow = _light_channel[0].shadow * ((float) _light_brightness / LIGHT_MAX_BRIGHTNESS); - _light_channel[2].shadow = 0; - _light_channel[1].shadow = 0; - _light_channel[0].shadow = 0; - } } } @@ -450,17 +483,19 @@ void _lightProviderUpdate() { void _lightColorSave() { for (unsigned int i=0; i < _light_channel.size(); i++) { - setSetting("ch", i, _light_channel[i].value); + setSetting("ch", i, _light_channel[i].inputValue); } setSetting("brightness", _light_brightness); + setSetting("mireds", _light_mireds); saveSettings(); } void _lightColorRestore() { for (unsigned int i=0; i < _light_channel.size(); i++) { - _light_channel[i].value = getSetting("ch", i, i==0 ? 255 : 0).toInt(); + _light_channel[i].inputValue = getSetting("ch", i, i==0 ? 255 : 0).toInt(); } _light_brightness = getSetting("brightness", LIGHT_MAX_BRIGHTNESS).toInt(); + _light_mireds = getSetting("mireds", _light_mireds).toInt(); lightUpdate(false, false); } @@ -471,6 +506,7 @@ void _lightColorRestore() { #if MQTT_SUPPORT void _lightMQTTCallback(unsigned int type, const char * topic, const char * payload) { + String mqtt_group_color = getSetting("mqttGroupColor"); if (type == MQTT_CONNECT_EVENT) { @@ -478,11 +514,14 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl mqttSubscribe(MQTT_TOPIC_BRIGHTNESS); mqttSubscribe(MQTT_TOPIC_MIRED); mqttSubscribe(MQTT_TOPIC_KELVIN); - mqttSubscribe(MQTT_TOPIC_COLOR); // DEPRECATE mqttSubscribe(MQTT_TOPIC_COLOR_RGB); mqttSubscribe(MQTT_TOPIC_COLOR_HSV); } + // Group color + if (mqtt_group_color.length() > 0) mqttSubscribeRaw(mqtt_group_color.c_str()); + + // Channels char buffer[strlen(MQTT_TOPIC_CHANNEL) + 3]; snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_CHANNEL); mqttSubscribe(buffer); @@ -491,35 +530,47 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl if (type == MQTT_MESSAGE_EVENT) { + // Group color + if ((mqtt_group_color.length() > 0) & (mqtt_group_color.equals(topic))) { + lightColor(payload, true); + lightUpdate(true, mqttForward(), false); + return; + } + // Match topic - String t = mqttSubtopic((char *) topic); + String t = mqttMagnitude((char *) topic); // Color temperature in mireds if (t.equals(MQTT_TOPIC_MIRED)) { _fromMireds(atol(payload)); lightUpdate(true, mqttForward()); + return; } // Color temperature in kelvins if (t.equals(MQTT_TOPIC_KELVIN)) { _fromKelvin(atol(payload)); lightUpdate(true, mqttForward()); + return; } // Color - if (t.equals(MQTT_TOPIC_COLOR) || t.equals(MQTT_TOPIC_COLOR_RGB)) { // DEPRECATE MQTT_TOPIC_COLOR + if (t.equals(MQTT_TOPIC_COLOR_RGB)) { lightColor(payload, true); lightUpdate(true, mqttForward()); + return; } if (t.equals(MQTT_TOPIC_COLOR_HSV)) { lightColor(payload, false); lightUpdate(true, mqttForward()); + return; } // Brightness if (t.equals(MQTT_TOPIC_BRIGHTNESS)) { _light_brightness = constrain(atoi(payload), 0, LIGHT_MAX_BRIGHTNESS); lightUpdate(true, mqttForward()); + return; } // Channel @@ -531,6 +582,7 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl } lightChannel(channelID, atoi(payload)); lightUpdate(true, mqttForward()); + return; } } @@ -538,19 +590,18 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl } void lightMQTT() { - - char buffer[12]; + char buffer[20]; if (_light_has_color) { // Color if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { - _toRGB(buffer, sizeof(buffer), false); + _toRGB(buffer, sizeof(buffer)); } else { - _toLong(buffer, sizeof(buffer), false); + _toLong(buffer, sizeof(buffer)); } - mqttSend(MQTT_TOPIC_COLOR, buffer); // DEPRECATE mqttSend(MQTT_TOPIC_COLOR_RGB, buffer); + _toHSV(buffer, sizeof(buffer)); mqttSend(MQTT_TOPIC_COLOR_HSV, buffer); @@ -558,16 +609,44 @@ void lightMQTT() { snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _light_brightness); mqttSend(MQTT_TOPIC_BRIGHTNESS, buffer); + // Mireds + snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _light_mireds); + mqttSend(MQTT_TOPIC_MIRED, buffer); } // Channels for (unsigned int i=0; i < _light_channel.size(); i++) { - snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _light_channel[i].value); + itoa(_light_channel[i].inputValue, buffer, 10); mqttSend(MQTT_TOPIC_CHANNEL, i, buffer); } } +void lightMQTTGroup() { + String mqtt_group_color = getSetting("mqttGroupColor"); + if (mqtt_group_color.length()>0) { + char buffer[20]; + _toCSV(buffer, sizeof(buffer), true); + mqttSendRaw(mqtt_group_color.c_str(), buffer); + } +} + +#endif + +// ----------------------------------------------------------------------------- +// Broker +// ----------------------------------------------------------------------------- + +#if BROKER_SUPPORT + +void lightBroker() { + char buffer[10]; + for (unsigned int i=0; i < _light_channel.size(); i++) { + itoa(_light_channel[i].inputValue, buffer, 10); + brokerPublish(MQTT_TOPIC_CHANNEL, i, buffer); + } +} + #endif // ----------------------------------------------------------------------------- @@ -582,19 +661,23 @@ bool lightHasColor() { return _light_has_color; } -unsigned char lightWhiteChannels() { - return _light_channel.size() % 3; -} +void lightUpdate(bool save, bool forward, bool group_forward) { -void lightUpdate(bool save, bool forward) { + _generateBrightness(); // Configure color transition - _light_steps_left = _light_use_transitions ? LIGHT_TRANSITION_STEPS : 1; + _light_steps_left = _light_use_transitions ? _light_transition_time / LIGHT_TRANSITION_STEP : 1; _light_transition_ticker.attach_ms(LIGHT_TRANSITION_STEP, _lightProviderUpdate); + // Report channels to local broker + #if BROKER_SUPPORT + lightBroker(); + #endif + // Report color & brightness to MQTT broker #if MQTT_SUPPORT if (forward) lightMQTT(); + if (group_forward) lightMQTTGroup(); #endif // Report color to WS clients (using current brightness setting) @@ -609,12 +692,24 @@ void lightUpdate(bool save, bool forward) { }; +void lightUpdate(bool save, bool forward) { + lightUpdate(save, forward, true); +} + #if LIGHT_SAVE_ENABLED == 0 void lightSave() { _lightColorSave(); } #endif +void lightState(unsigned char i, bool state) { + _light_channel[i].state = state; +} + +bool lightState(unsigned char i) { + return _light_channel[i].state; +} + void lightState(bool state) { _light_state = state; } @@ -643,7 +738,7 @@ void lightColor(unsigned long color) { String lightColor(bool rgb) { char str[12]; if (rgb) { - _toRGB(str, sizeof(str), false); + _toRGB(str, sizeof(str)); } else { _toHSV(str, sizeof(str)); } @@ -656,14 +751,14 @@ String lightColor() { unsigned int lightChannel(unsigned char id) { if (id <= _light_channel.size()) { - return _light_channel[id].value; + return _light_channel[id].inputValue; } return 0; } void lightChannel(unsigned char id, unsigned int value) { if (id <= _light_channel.size()) { - _light_channel[id].value = constrain(value, 0, LIGHT_MAX_VALUE); + _light_channel[id].inputValue = constrain(value, 0, LIGHT_MAX_VALUE); } } @@ -685,16 +780,28 @@ void lightBrightnessStep(int steps) { #if WEB_SUPPORT +bool _lightWebSocketOnReceive(const char * key, JsonVariant& value) { + if (strncmp(key, "light", 5) == 0) return true; + if (strncmp(key, "use", 3) == 0) return true; + return false; +} + void _lightWebSocketOnSend(JsonObject& root) { root["colorVisible"] = 1; + root["mqttGroupColor"] = getSetting("mqttGroupColor"); root["useColor"] = _light_has_color; root["useWhite"] = _light_use_white; root["useGamma"] = _light_use_gamma; root["useTransitions"] = _light_use_transitions; + root["lightTime"] = _light_transition_time; root["useCSS"] = getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1; bool useRGB = getSetting("useRGB", LIGHT_USE_RGB).toInt() == 1; root["useRGB"] = useRGB; if (_light_has_color) { + if (_light_use_cct) { + root["useCCT"] = _light_use_cct; + root["mireds"] = _light_mireds; + } if (useRGB) { root["rgb"] = lightColor(true); root["brightness"] = lightBrightness(); @@ -703,15 +810,13 @@ void _lightWebSocketOnSend(JsonObject& root) { } } JsonArray& channels = root.createNestedArray("channels"); - for (unsigned char id=0; id < lightChannels(); id++) { + for (unsigned char id=0; id < _light_channel.size(); id++) { channels.add(lightChannel(id)); } } -void _lightWebSocketOnAction(const char * action, JsonObject& data) { - +void _lightWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) { if (_light_has_color) { - if (strcmp(action, "color") == 0) { if (data.containsKey("rgb")) { lightColor(data["rgb"], true); @@ -726,7 +831,12 @@ void _lightWebSocketOnAction(const char * action, JsonObject& data) { lightUpdate(true, true); } } - + if (_light_use_cct) { + if (strcmp(action, "mireds") == 0) { + _fromMireds(data["mireds"]); + lightUpdate(true, true); + } + } } if (strcmp(action, "channel") == 0) { @@ -735,102 +845,140 @@ void _lightWebSocketOnAction(const char * action, JsonObject& data) { lightUpdate(true, true); } } - } void _lightAPISetup() { - - // API entry points (protected with apikey) - if (_light_has_color) { - - // DEPRECATE - apiRegister(MQTT_TOPIC_COLOR, - [](char * buffer, size_t len) { - if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { - _toRGB(buffer, len, false); - } else { - _toLong(buffer, len, false); - } - }, - [](const char * payload) { - lightColor(payload, true); - lightUpdate(true, true); + // API entry points (protected with apikey) + if (_light_has_color) { + apiRegister(MQTT_TOPIC_COLOR_RGB, + [](char * buffer, size_t len) { + if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { + _toRGB(buffer, len); + } else { + _toLong(buffer, len); } - ); + }, + [](const char * payload) { + lightColor(payload, true); + lightUpdate(true, true); + } + ); - apiRegister(MQTT_TOPIC_COLOR_RGB, - [](char * buffer, size_t len) { - if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { - _toRGB(buffer, len, false); - } else { - _toLong(buffer, len, false); - } - }, - [](const char * payload) { - lightColor(payload, true); - lightUpdate(true, true); - } - ); - - apiRegister(MQTT_TOPIC_COLOR_HSV, - [](char * buffer, size_t len) { - _toHSV(buffer, len); - }, - [](const char * payload) { - lightColor(payload, false); - lightUpdate(true, true); - } - ); - - apiRegister(MQTT_TOPIC_BRIGHTNESS, - [](char * buffer, size_t len) { - snprintf_P(buffer, len, PSTR("%d"), _light_brightness); - }, - [](const char * payload) { - lightBrightness(atoi(payload)); - lightUpdate(true, true); - } - ); + apiRegister(MQTT_TOPIC_COLOR_HSV, + [](char * buffer, size_t len) { + _toHSV(buffer, len); + }, + [](const char * payload) { + lightColor(payload, false); + lightUpdate(true, true); + } + ); - apiRegister(MQTT_TOPIC_KELVIN, - [](char * buffer, size_t len) {}, - [](const char * payload) { - _fromKelvin(atol(payload)); - lightUpdate(true, true); - } - ); + apiRegister(MQTT_TOPIC_BRIGHTNESS, + [](char * buffer, size_t len) { + snprintf_P(buffer, len, PSTR("%d"), _light_brightness); + }, + [](const char * payload) { + lightBrightness(atoi(payload)); + lightUpdate(true, true); + } + ); - apiRegister(MQTT_TOPIC_MIRED, - [](char * buffer, size_t len) {}, - [](const char * payload) { - _fromMireds(atol(payload)); - lightUpdate(true, true); - } - ); + apiRegister(MQTT_TOPIC_KELVIN, + [](char * buffer, size_t len) {}, + [](const char * payload) { + _fromKelvin(atol(payload)); + lightUpdate(true, true); + } + ); - } + apiRegister(MQTT_TOPIC_MIRED, + [](char * buffer, size_t len) {}, + [](const char * payload) { + _fromMireds(atol(payload)); + lightUpdate(true, true); + } + ); + } + + for (unsigned int id=0; id<_light_channel.size(); id++) { + char key[15]; + snprintf_P(key, sizeof(key), PSTR("%s/%d"), MQTT_TOPIC_CHANNEL, id); + + apiRegister(key, + [id](char * buffer, size_t len) { + snprintf_P(buffer, len, PSTR("%d"), lightChannel(id)); + }, + [id](const char * payload) { + lightChannel(id, atoi(payload)); + lightUpdate(true, true); + } + ); + } +} - for (unsigned int id=0; idargc > 1) { + lightBrightness(String(e->argv[1]).toInt()); + lightUpdate(true, true); + } + DEBUG_MSG_P(PSTR("Brightness: %d\n"), lightBrightness()); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + settingsRegisterCommand(F("CHANNEL"), [](Embedis* e) { + if (e->argc < 2) { + DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); + } + int id = String(e->argv[1]).toInt(); + if (e->argc > 2) { + int value = String(e->argv[2]).toInt(); + lightChannel(id, value); + lightUpdate(true, true); + } + DEBUG_MSG_P(PSTR("Channel #%d: %d\n"), id, lightChannel(id)); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + + settingsRegisterCommand(F("COLOR"), [](Embedis* e) { + if (e->argc > 1) { + String color = String(e->argv[1]); + lightColor(color.c_str()); + lightUpdate(true, true); + } + DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + + settingsRegisterCommand(F("KELVIN"), [](Embedis* e) { + if (e->argc > 1) { + String color = String("K") + String(e->argv[1]); + lightColor(color.c_str()); + lightUpdate(true, true); + } + DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + + settingsRegisterCommand(F("MIRED"), [](Embedis* e) { + if (e->argc > 1) { + String color = String("M") + String(e->argv[1]); + lightColor(color.c_str()); + lightUpdate(true, true); + } + DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); + DEBUG_MSG_P(PSTR("+OK\n")); + }); } -#endif // WEB_SUPPORT +#endif // TERMINAL_SUPPORT #if LIGHT_PROVIDER == LIGHT_PROVIDER_DIMMER @@ -870,8 +1018,15 @@ void _lightConfigure() { setSetting("useWhite", _light_use_white); } + _light_use_cct = getSetting("useCCT", LIGHT_USE_CCT).toInt() == 1; + if (_light_use_cct && ((_light_channel.size() < 5) || !_light_use_white)) { + _light_use_cct = false; + setSetting("useCCT", _light_use_cct); + } + _light_use_gamma = getSetting("useGamma", LIGHT_USE_GAMMA).toInt() == 1; _light_use_transitions = getSetting("useTransitions", LIGHT_USE_TRANSITIONS).toInt() == 1; + _light_transition_time = getSetting("lightTime", LIGHT_TRANSITION_TIME).toInt(); } @@ -886,7 +1041,7 @@ void lightSetup() { _my92xx = new my92xx(MY92XX_MODEL, MY92XX_CHIPS, MY92XX_DI_PIN, MY92XX_DCKI_PIN, MY92XX_COMMAND); for (unsigned char i=0; i +Copyright (C) 2017-2018 by Xose Pérez */ diff --git a/code/espurna/mdns.ino b/code/espurna/mdns.ino index 1cdc689e..45610dac 100644 --- a/code/espurna/mdns.ino +++ b/code/espurna/mdns.ino @@ -2,19 +2,21 @@ MDNS MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez */ -#if MDNS_SUPPORT +// ----------------------------------------------------------------------------- +// mDNS Server +// ----------------------------------------------------------------------------- -#include +#if MDNS_SERVER_SUPPORT -WiFiEventHandler _mdns_wifi_onSTA; -WiFiEventHandler _mdns_wifi_onAP; +#include #if MQTT_SUPPORT -void mdnsFindMQTT() { + +void _mdnsFindMQTT() { int count = MDNS.queryService("mqtt", "tcp"); DEBUG_MSG_P(PSTR("[MQTT] MQTT brokers found: %d\n"), count); for (int i=0; i +#include + +using namespace mDNSResolver; +WiFiUDP _mdns_udp; +Resolver _mdns_resolver(_mdns_udp); + +String mdnsResolve(char * name) { + + if (strlen(name) == 0) return String(); + if (WiFi.status() != WL_CONNECTED) return String(); + + _mdns_resolver.setLocalIP(WiFi.localIP()); + IPAddress ip = _mdns_resolver.search(name); + + if (ip == INADDR_NONE) return String(name); + DEBUG_MSG_P(PSTR("[MDNS] '%s' resolved to '%s'\n"), name, ip.toString().c_str()); + return ip.toString(); + +} + +String mdnsResolve(String name) { + return mdnsResolve((char *) name.c_str()); +} + +void mdnsClientSetup() { + + // Register loop + espurnaRegisterLoop(mdnsClientLoop); + +} + +void mdnsClientLoop() { + _mdns_resolver.loop(); +} + +#endif // MDNS_CLIENT_SUPPORT diff --git a/code/espurna/migrate.ino b/code/espurna/migrate.ino index c4563fb1..5cec4fd2 100644 --- a/code/espurna/migrate.ino +++ b/code/espurna/migrate.ino @@ -2,7 +2,7 @@ MIGRATE MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -683,9 +683,330 @@ void migrate() { setSetting("chLogic", 4, 0); setSetting("relays", 1); + #elif defined(ARILUX_AL_LC02) + + setSetting("board", 52); + setSetting("relayProvider", RELAY_PROVIDER_LIGHT); + setSetting("lightProvider", LIGHT_PROVIDER_DIMMER); + setSetting("chGPIO", 0, 12); + setSetting("chGPIO", 1, 5); + setSetting("chGPIO", 2, 13); + setSetting("chGPIO", 3, 15); + setSetting("chLogic", 0, 0); + setSetting("chLogic", 1, 0); + setSetting("chLogic", 2, 0); + setSetting("chLogic", 3, 0); + setSetting("relays", 1); + + #elif defined(KMC_70011) + + setSetting("board", 53); + setSetting("ledGPIO", 0, 13); + setSetting("ledLogic", 0, 0); + setSetting("btnGPIO", 0, 0); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 14); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("selGPIO", 12); + setSetting("cf1GPIO", 5); + setSetting("cfGPIO", 4); + + #elif defined(GIZWITS_WITTY_CLOUD) + + setSetting("board", 54); + setSetting("ledGPIO", 0, 2); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 4); + setSetting("relayProvider", RELAY_PROVIDER_LIGHT); + setSetting("lightProvider", LIGHT_PROVIDER_DIMMER); + setSetting("chGPIO", 0, 15); + setSetting("chGPIO", 1, 12); + setSetting("chGPIO", 2, 13); + setSetting("chLogic", 0, 0); + setSetting("chLogic", 1, 0); + setSetting("chLogic", 2, 0); + setSetting("relays", 1); + + #elif defined(EUROMATE_WIFI_STECKER_SCHUKO) + + setSetting("board", 55); + setSetting("ledGPIO", 0, 4); + setSetting("ledLogic", 0, 0); + setSetting("ledGPIO", 1, 12); + setSetting("ledLogic", 1, 0); + setSetting("btnGPIO", 0, 14); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 5); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(TONBUX_POWERSTRIP02) + + setSetting("board", 56); + setSetting("relayGPIO", 0, 4); + setSetting("relayGPIO", 1, 13); + setSetting("relayGPIO", 2, 12); + setSetting("relayGPIO", 3, 14); + setSetting("relayGPIO", 4, 16); + setSetting("relayType", 0, RELAY_TYPE_INVERSE); + setSetting("relayType", 1, RELAY_TYPE_INVERSE); + setSetting("relayType", 2, RELAY_TYPE_INVERSE); + setSetting("relayType", 3, RELAY_TYPE_INVERSE); + setSetting("relayType", 4, RELAY_TYPE_NORMAL); // Not a relay. USB ports on/off + setSetting("ledGPIO", 0, 0); // 1 blue led + setSetting("ledLogic", 0, 1); + setSetting("ledGPIO", 1, 3); // 3 red leds + setSetting("ledLogic", 1, 1); + setSetting("btnGPIO", 0, 5); + setSetting("btnRelay", 0, 1); + + #elif defined(LINGAN_SWA1) + + setSetting("board", 57); + setSetting("ledGPIO", 0, 4); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 13); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 5); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(HEYGO_HY02) + + setSetting("board", 58); + setSetting("ledGPIO", 0, 0); + setSetting("ledLogic", 0, 1); + setSetting("ledGPIO", 1, 15); + setSetting("ledLogic", 1, 0); + setSetting("btnGPIO", 0, 13); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 15); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("selGPIO", 3); + setSetting("cf1GPIO", 14); + setSetting("cfGPIO", 5); + + #elif defined(MAXCIO_WUS002S) + + setSetting("board", 59); + setSetting("ledGPIO", 0, 3); + setSetting("ledLogic", 0, 0); + setSetting("btnGPIO", 0, 2); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 13); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("selGPIO", 12); + setSetting("cf1GPIO", 5); + setSetting("cfGPIO", 4); + + #elif defined(YIDIAN_XSSSA05) + + setSetting("board", 60); + setSetting("ledGPIO", 0, 0); + setSetting("ledLogic", 0, 0); + setSetting("ledGPIO", 1, 5); + setSetting("ledLogic", 1, 0); + setSetting("ledGPIO", 2, 2); + setSetting("ledLogic", 2, 0); + setSetting("btnGPIO", 0, 13); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 15); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(TONBUX_XSSSA06) + + setSetting("board", 61); + setSetting("ledGPIO", 0, 4); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 13); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 5); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(GREEN_ESP8266RELAY) + + setSetting("board", 62); + setSetting("ledGPIO", 0, 2); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 5); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 4); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(IKE_ESPIKE) + + setSetting("board", 63); + setSetting("ledGPIO", 0, 2); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 13); + setSetting("btnRelay", 0, 0); + setSetting("btnGPIO", 1, 12); + setSetting("btnRelay", 1, 1); + setSetting("btnGPIO", 2, 13); + setSetting("btnRelay", 2, 2); + setSetting("relayGPIO", 0, 4); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("relayGPIO", 1, 5); + setSetting("relayType", 1, RELAY_TYPE_NORMAL); + setSetting("relayGPIO", 2, 16); + setSetting("relayType", 2, RELAY_TYPE_NORMAL); + + #elif defined(ARNIEX_SWIFITCH) + + setSetting("board", 64); + setSetting("ledGPIO", 0, 12); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 4); + setSetting("btnRelay", 0, 1); + setSetting("relayGPIO", 0, 5); + setSetting("relayType", 0, RELAY_TYPE_INVERSE); + + #elif defined(GENERIC_ESP01S_RELAY_V40) + + setSetting("board", 65); + setSetting("ledGPIO", 0, 2); + setSetting("ledLogic", 0, 0); + setSetting("relayGPIO", 0, 0); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(GENERIC_ESP01S_RGBLED_V10) + + setSetting("board", 66); + setSetting("ledGPIO", 0, 2); + + #elif defined(HELTEC_TOUCHRELAY) + + setSetting("board", 67); + setSetting("btnGPIO", 0, 14); + setSetting("btnRelay", 0, 1); + setSetting("relayGPIO", 0, 12); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(GENERIC_ESP01S_DHT11_V10) + + setSetting("board", 68); + + #elif defined(GENERIC_ESP01S_DS18B20_V10) + + setSetting("board", 69); + + #elif defined(ZHILDE_EU44_W) + + setSetting("board", 70); + setSetting("btnGPIO", 0, 3); + setSetting("ledGPIO", 0, 1); + setSetting("ledLogic", 0, 1); + setSetting("relayGPIO", 0, 5); + setSetting("relayGPIO", 1, 4); + setSetting("relayGPIO", 2, 12); + setSetting("relayGPIO", 3, 13); + setSetting("relayGPIO", 4, 14); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("relayType", 1, RELAY_TYPE_NORMAL); + setSetting("relayType", 2, RELAY_TYPE_NORMAL); + setSetting("relayType", 3, RELAY_TYPE_NORMAL); + setSetting("relayType", 4, RELAY_TYPE_NORMAL); + + #elif defined(ITEAD_SONOFF_POW_R2) + + setSetting("board", 71); + setSetting("ledGPIO", 0, 15); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 0); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 12); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("selGPIO", 5); + setSetting("cf1GPIO", 13); + setSetting("cfGPIO", 14); + + #elif defined(LUANI_HVIO) + + setSetting("board", 72); + setSetting("ledGPIO", 0, 15); + setSetting("ledLogic", 0, 0); + setSetting("btnGPIO", 0, 12); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 4); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("relayGPIO", 1, 5); + setSetting("relayType", 1, RELAY_TYPE_NORMAL); + + #elif defined(ALLNET_4DUINO_IOT_WLAN_RELAIS) + + setSetting("board", 73); + setSetting("relayGPIO", 0, 14); + setSetting("relayResetGPIO", 0, 12); + setSetting("relayType", 0, RELAY_TYPE_LATCHED); + + #elif defined(TONBUX_MOSQUITO_KILLER) + + setSetting("board", 74); + setSetting("ledGPIO", 0, 15); + setSetting("ledLogic", 0, 1); + setSetting("ledGPIO", 1, 14); + setSetting("ledLogic", 1, 1); + setSetting("ledGPIO", 2, 12); + setSetting("ledLogic", 2, 0); + setSetting("ledGPIO", 3, 16); + setSetting("ledLogic", 3, 0); + setSetting("btnGPIO", 0, 2); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 5); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(NEO_COOLCAM_POWER_PLUG_WIFI) + + setSetting("board", 75); + setSetting("ledGPIO", 0, 4); + setSetting("ledLogic", 0, 1); + setSetting("btnGPIO", 0, 13); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 12); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + + #elif defined(PILOTAK_ESP_DIN_V1) + + setSetting("board", 76); + setSetting("ledGPIO", 0, 16); + setSetting("ledLogic", 0, 0); + setSetting("btnGPIO", 0, 0); + setSetting("btnRelay", 0, 0); + setSetting("relayGPIO", 0, 4); + setSetting("relayGPIO", 1, 5); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("relayType", 1, RELAY_TYPE_NORMAL); + + #elif defined(ESTINK_WIFI_POWER_STRIP) + + setSetting("board", 76); + setSetting("btnGPIO", 0, 16); + setSetting("btnRelay", 0, 3); + setSetting("ledGPIO", 0, 0); + setSetting("ledGPIO", 1, 12); + setSetting("ledGPIO", 2, 3); + setSetting("ledGPIO", 3, 5); + setSetting("ledLogic", 0, 1); + setSetting("ledLogic", 1, 1); + setSetting("ledLogic", 2, 1); + setSetting("ledLogic", 3, 1); + setSetting("ledMode", 0, LED_MODE_FINDME); + setSetting("ledMode", 1, LED_MODE_FOLLOW); + setSetting("ledMode", 2, LED_MODE_FOLLOW); + setSetting("ledMode", 3, LED_MODE_FOLLOW); + setSetting("ledRelay", 1, 1); + setSetting("ledRelay", 2, 2); + setSetting("ledRelay", 3, 3); + setSetting("relayGPIO", 0, 14); + setSetting("relayGPIO", 1, 13); + setSetting("relayGPIO", 2, 4); + setSetting("relayGPIO", 3, 15); + setSetting("relayType", 0, RELAY_TYPE_NORMAL); + setSetting("relayType", 1, RELAY_TYPE_NORMAL); + setSetting("relayType", 2, RELAY_TYPE_NORMAL); + setSetting("relayType", 3, RELAY_TYPE_NORMAL); + #elif defined(GENERIC_FASTLED) - setSetting("board", 51); + setSetting("board", 77); setSetting("relayProvider", RELAY_PROVIDER_LIGHT); setSetting("lightProvider", LIGHT_PROVIDER_FASTLED); setSetting("dataGPIO", 0, 5); diff --git a/code/espurna/mqtt.ino b/code/espurna/mqtt.ino index 05a71958..fa02afde 100644 --- a/code/espurna/mqtt.ino +++ b/code/espurna/mqtt.ino @@ -2,12 +2,13 @@ MQTT MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ #if MQTT_SUPPORT +#include #include #include #include @@ -37,14 +38,16 @@ bool _mqtt_use_json = false; unsigned long _mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN; unsigned char _mqtt_qos = MQTT_QOS; bool _mqtt_retain = MQTT_RETAIN; -unsigned char _mqtt_keepalive = MQTT_KEEPALIVE; +unsigned long _mqtt_keepalive = MQTT_KEEPALIVE; String _mqtt_topic; +String _mqtt_topic_json; String _mqtt_setter; String _mqtt_getter; bool _mqtt_forward; char *_mqtt_user = 0; char *_mqtt_pass = 0; char *_mqtt_will; +char *_mqtt_clientid; #if MQTT_SKIP_RETAINED unsigned long _mqtt_connected_at = 0; #endif @@ -52,195 +55,321 @@ unsigned long _mqtt_connected_at = 0; std::vector _mqtt_callbacks; typedef struct { + unsigned char parent = 255; char * topic; - char * message; + char * message = NULL; } mqtt_message_t; std::vector _mqtt_queue; Ticker _mqtt_flush_ticker; // ----------------------------------------------------------------------------- -// Public API +// Private // ----------------------------------------------------------------------------- -bool mqttConnected() { - return _mqtt.connected(); -} +void _mqttConnect() { -void mqttDisconnect() { - if (_mqtt.connected()) { - DEBUG_MSG_P(PSTR("[MQTT] Disconnecting\n")); - _mqtt.disconnect(); - } -} + // Do not connect if disabled + if (!_mqtt_enabled) return; -bool mqttForward() { - return _mqtt_forward; -} + // Do not connect if already connected + if (_mqtt.connected()) return; -String mqttSubtopic(char * topic) { - String response; - String t = String(topic); - if (t.startsWith(_mqtt_topic) && t.endsWith(_mqtt_setter)) { - response = t.substring(_mqtt_topic.length(), t.length() - _mqtt_setter.length()); - } - return response; -} + // Check reconnect interval + static unsigned long last = 0; + if (millis() - last < _mqtt_reconnect_delay) return; + last = millis(); -void mqttSendRaw(const char * topic, const char * message) { - if (_mqtt.connected()) { - #if MQTT_USE_ASYNC - unsigned int packetId = _mqtt.publish(topic, _mqtt_qos, _mqtt_retain, message); - DEBUG_MSG_P(PSTR("[MQTT] Sending %s => %s (PID %d)\n"), topic, message, packetId); - #else - _mqtt.publish(topic, message, _mqtt_retain); - DEBUG_MSG_P(PSTR("[MQTT] Sending %s => %s\n"), topic, message); - #endif + // Increase the reconnect delay + _mqtt_reconnect_delay += MQTT_RECONNECT_DELAY_STEP; + if (_mqtt_reconnect_delay > MQTT_RECONNECT_DELAY_MAX) { + _mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MAX; } -} -String getTopic(const char * topic, bool set) { - String output = _mqtt_topic + String(topic); - if (set) output += _mqtt_setter; - return output; -} + String h = getSetting("mqttServer", MQTT_SERVER); + #if MDNS_CLIENT_SUPPORT + h = mdnsResolve(h); + #endif + char * host = strdup(h.c_str()); -String getTopic(const char * topic, unsigned int index, bool set) { - char buffer[strlen(topic)+5]; - snprintf_P(buffer, sizeof(buffer), PSTR("%s/%d"), topic, index); - return getTopic(buffer, set); -} + unsigned int port = getSetting("mqttPort", MQTT_PORT).toInt(); -void _mqttFlush() { + if (_mqtt_user) free(_mqtt_user); + if (_mqtt_pass) free(_mqtt_pass); + if (_mqtt_will) free(_mqtt_will); + if (_mqtt_clientid) free(_mqtt_clientid); - if (_mqtt_queue.size() == 0) return; + _mqtt_user = strdup(getSetting("mqttUser", MQTT_USER).c_str()); + _mqtt_pass = strdup(getSetting("mqttPassword", MQTT_PASS).c_str()); + _mqtt_will = strdup(mqttTopic(MQTT_TOPIC_STATUS, false).c_str()); + _mqtt_clientid = strdup(getSetting("mqttClientID", getIdentifier()).c_str()); - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.createObject(); - for (unsigned char i=0; i<_mqtt_queue.size(); i++) { - mqtt_message_t element = _mqtt_queue[i]; - root[element.topic] = element.message; - } - #if NTP_SUPPORT - if (ntpConnected()) root[MQTT_TOPIC_TIME] = ntpDateTime(); - #endif - root[MQTT_TOPIC_HOSTNAME] = getSetting("hostname"); - root[MQTT_TOPIC_IP] = getIP(); + DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%d\n"), host, port); - String output; - root.printTo(output); - String path = _mqtt_topic + String(MQTT_TOPIC_JSON); - mqttSendRaw(path.c_str(), output.c_str()); + #if MQTT_USE_ASYNC - for (unsigned char i = 0; i < _mqtt_queue.size(); i++) { - mqtt_message_t element = _mqtt_queue[i]; - free(element.topic); - free(element.message); - } - _mqtt_queue.clear(); + _mqtt.setServer(host, port); + _mqtt.setClientId(_mqtt_clientid); + _mqtt.setKeepAlive(_mqtt_keepalive); + _mqtt.setCleanSession(false); + _mqtt.setWill(_mqtt_will, _mqtt_qos, _mqtt_retain, "0"); + if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) { + DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user); + _mqtt.setCredentials(_mqtt_user, _mqtt_pass); + } + + #if ASYNC_TCP_SSL_ENABLED + + bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1; + _mqtt.setSecure(secure); + if (secure) { + DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n")); + unsigned char fp[20] = {0}; + if (sslFingerPrintArray(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) { + _mqtt.addServerFingerprint(fp); + } else { + DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n")); + } + } + + #endif // ASYNC_TCP_SSL_ENABLED + + DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid); + DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos); + DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0); + DEBUG_MSG_P(PSTR("[MQTT] Keepalive time: %ds\n"), _mqtt_keepalive); + DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will); + + _mqtt.connect(); + + #else // not MQTT_USE_ASYNC + + bool response = true; + + #if ASYNC_TCP_SSL_ENABLED + + bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1; + if (secure) { + DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n")); + if (_mqtt_client_secure.connect(host, port)) { + char fp[60] = {0}; + if (sslFingerPrintChar(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) { + if (_mqtt_client_secure.verify(fp, host)) { + _mqtt.setClient(_mqtt_client_secure); + } else { + DEBUG_MSG_P(PSTR("[MQTT] Invalid fingerprint\n")); + response = false; + } + _mqtt_client_secure.stop(); + yield(); + } else { + DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n")); + response = false; + } + } else { + DEBUG_MSG_P(PSTR("[MQTT] Client connection failed\n")); + response = false; + } + + } else { + _mqtt.setClient(_mqtt_client); + } + + #else // not ASYNC_TCP_SSL_ENABLED + + _mqtt.setClient(_mqtt_client); + + #endif // ASYNC_TCP_SSL_ENABLED + + if (response) { + + _mqtt.setServer(host, port); + + if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) { + DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user); + response = _mqtt.connect(_mqtt_clientid, _mqtt_user, _mqtt_pass, _mqtt_will, _mqtt_qos, _mqtt_retain, "0"); + } else { + response = _mqtt.connect(_mqtt_clientid, _mqtt_will, _mqtt_qos, _mqtt_retain, "0"); + } + + DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid); + DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos); + DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0); + DEBUG_MSG_P(PSTR("[MQTT] Keepalive time: %ds\n"), _mqtt_keepalive); + DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will); + + } + + if (response) { + _mqttOnConnect(); + } else { + DEBUG_MSG_P(PSTR("[MQTT] Connection failed\n")); + } + + #endif // MQTT_USE_ASYNC + + free(host); } -void mqttSend(const char * topic, const char * message, bool force) { - bool useJson = force ? false : _mqtt_use_json; - if (useJson) { +void _mqttConfigure() { - if (_mqtt_queue.size() >= MQTT_QUEUE_MAX_SIZE) _mqttFlush(); + // Get base topic + _mqtt_topic = getSetting("mqttTopic", MQTT_TOPIC); + if (_mqtt_topic.endsWith("/")) _mqtt_topic.remove(_mqtt_topic.length()-1); - mqtt_message_t element; - element.topic = strdup(topic); - element.message = strdup(message); - _mqtt_queue.push_back(element); - _mqtt_flush_ticker.once_ms(MQTT_USE_JSON_DELAY, _mqttFlush); + // Placeholders + _mqtt_topic.replace("{hostname}", getSetting("hostname")); + _mqtt_topic.replace("{magnitude}", "#"); + if (_mqtt_topic.indexOf("#") == -1) _mqtt_topic = _mqtt_topic + "/#"; + String mac = WiFi.macAddress(); + mac.replace(":", ""); + _mqtt_topic.replace("{mac}", mac); + + // Getters and setters + _mqtt_setter = getSetting("mqttSetter", MQTT_SETTER); + _mqtt_getter = getSetting("mqttGetter", MQTT_GETTER); + _mqtt_forward = !_mqtt_getter.equals(_mqtt_setter); + + // MQTT options + _mqtt_qos = getSetting("mqttQoS", MQTT_QOS).toInt(); + _mqtt_retain = getSetting("mqttRetain", MQTT_RETAIN).toInt() == 1; + _mqtt_keepalive = getSetting("mqttKeep", MQTT_KEEPALIVE).toInt(); + if (getSetting("mqttClientID").length() == 0) delSetting("mqttClientID"); + // Enable + if (getSetting("mqttServer", MQTT_SERVER).length() == 0) { + mqttEnabled(false); } else { - String path = _mqtt_topic + String(topic) + _mqtt_getter; - mqttSendRaw(path.c_str(), message); + _mqtt_enabled = getSetting("mqttEnabled", MQTT_ENABLED).toInt() == 1; } -} - -void mqttSend(const char * topic, const char * message) { - mqttSend(topic, message, false); -} + _mqtt_use_json = (getSetting("mqttUseJson", MQTT_USE_JSON).toInt() == 1); + mqttQueueTopic(MQTT_TOPIC_JSON); -void mqttSend(const char * topic, unsigned int index, const char * message, bool force) { - char buffer[strlen(topic)+5]; - snprintf_P(buffer, sizeof(buffer), PSTR("%s/%d"), topic, index); - mqttSend(buffer, message, force); -} + _mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN; -void mqttSend(const char * topic, unsigned int index, const char * message) { - mqttSend(topic, index, message, false); } -void mqttSubscribeRaw(const char * topic) { - if (_mqtt.connected() && (strlen(topic) > 0)) { - #if MQTT_USE_ASYNC - unsigned int packetId = _mqtt.subscribe(topic, _mqtt_qos); - DEBUG_MSG_P(PSTR("[MQTT] Subscribing to %s (PID %d)\n"), topic, packetId); - #else - _mqtt.subscribe(topic, _mqtt_qos); - DEBUG_MSG_P(PSTR("[MQTT] Subscribing to %s\n"), topic); - #endif +void _mqttBackwards() { + String mqttTopic = getSetting("mqttTopic", MQTT_TOPIC); + if (mqttTopic.indexOf("{identifier}") > 0) { + mqttTopic.replace("{identifier}", "{hostname}"); + setSetting("mqttTopic", mqttTopic); } } -void mqttSubscribe(const char * topic) { - String path = _mqtt_topic + String(topic) + _mqtt_setter; - mqttSubscribeRaw(path.c_str()); -} +unsigned long _mqttNextMessageId() { + + static unsigned long id = 0; + + // just reboot, get last count from EEPROM + if (id == 0) { + + // read id from EEPROM and shift it + id = EEPROMr.read(EEPROM_MESSAGE_ID); + if (id == 0xFF) { + + // There was nothing in EEPROM, + // next message is first message + id = 0; + + } else { + + id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 1); + id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 2); + id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 3); + + // Calculate next block and start from there + id = MQTT_MESSAGE_ID_SHIFT * (1 + (id / MQTT_MESSAGE_ID_SHIFT)); + + } -void mqttUnsubscribeRaw(const char * topic) { - if (_mqtt.connected() && (strlen(topic) > 0)) { - #if MQTT_USE_ASYNC - unsigned int packetId = _mqtt.unsubscribe(topic); - DEBUG_MSG_P(PSTR("[MQTT] Unsubscribing to %s (PID %d)\n"), topic, packetId); - #else - _mqtt.unsubscribe(topic); - DEBUG_MSG_P(PSTR("[MQTT] Unsubscribing to %s\n"), topic); - #endif } -} -void mqttRegister(mqtt_callback_f callback) { - _mqtt_callbacks.push_back(callback); + // Save to EEPROM every MQTT_MESSAGE_ID_SHIFT + if (id % MQTT_MESSAGE_ID_SHIFT == 0) { + EEPROMr.write(EEPROM_MESSAGE_ID + 0, (id >> 24) & 0xFF); + EEPROMr.write(EEPROM_MESSAGE_ID + 1, (id >> 16) & 0xFF); + EEPROMr.write(EEPROM_MESSAGE_ID + 2, (id >> 8) & 0xFF); + EEPROMr.write(EEPROM_MESSAGE_ID + 3, (id >> 0) & 0xFF); + EEPROMr.commit(); + } + + id++; + return id; + } // ----------------------------------------------------------------------------- -// Callbacks +// WEB // ----------------------------------------------------------------------------- +#if WEB_SUPPORT + +bool _mqttWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "mqtt", 3) == 0); +} + void _mqttWebSocketOnSend(JsonObject& root) { root["mqttVisible"] = 1; root["mqttStatus"] = mqttConnected(); root["mqttEnabled"] = mqttEnabled(); root["mqttServer"] = getSetting("mqttServer", MQTT_SERVER); root["mqttPort"] = getSetting("mqttPort", MQTT_PORT); - root["mqttUser"] = getSetting("mqttUser"); - root["mqttPassword"] = getSetting("mqttPassword"); + root["mqttUser"] = getSetting("mqttUser", MQTT_USER); + root["mqttClientID"] = getSetting("mqttClientID"); + root["mqttPassword"] = getSetting("mqttPassword", MQTT_PASS); root["mqttKeep"] = _mqtt_keepalive; root["mqttRetain"] = _mqtt_retain; root["mqttQoS"] = _mqtt_qos; #if ASYNC_TCP_SSL_ENABLED root["mqttsslVisible"] = 1; - root["mqttUseSSL"] = getSetting("mqttUseSSL", 0).toInt() == 1; - root["mqttFP"] = getSetting("mqttFP"); + root["mqttUseSSL"] = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1; + root["mqttFP"] = getSetting("mqttFP", MQTT_SSL_FINGERPRINT); #endif root["mqttTopic"] = getSetting("mqttTopic", MQTT_TOPIC); root["mqttUseJson"] = getSetting("mqttUseJson", MQTT_USE_JSON).toInt() == 1; } +#endif + +// ----------------------------------------------------------------------------- +// SETTINGS +// ----------------------------------------------------------------------------- + +#if TERMINAL_SUPPORT + +void _mqttInitCommands() { + + settingsRegisterCommand(F("MQTT.RESET"), [](Embedis* e) { + _mqttConfigure(); + mqttDisconnect(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + +} + +#endif // TERMINAL_SUPPORT + +// ----------------------------------------------------------------------------- +// MQTT Callbacks +// ----------------------------------------------------------------------------- + void _mqttCallback(unsigned int type, const char * topic, const char * payload) { if (type == MQTT_CONNECT_EVENT) { + // Subscribe to internal action topics mqttSubscribe(MQTT_TOPIC_ACTION); + // Flag system to send heartbeat + systemSendHeartbeat(); + } if (type == MQTT_MESSAGE_EVENT) { // Match topic - String t = mqttSubtopic((char *) topic); + String t = mqttMagnitude((char *) topic); // Actions if (t.equals(MQTT_TOPIC_ACTION)) { @@ -305,216 +434,299 @@ void _mqttOnMessage(char* topic, char* payload, unsigned int len) { } -#if MQTT_USE_ASYNC - -bool mqttFormatFP(const char * fingerprint, unsigned char * bytearray) { - - // check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59) - if (strlen(fingerprint) != 59) return false; +// ----------------------------------------------------------------------------- +// Public API +// ----------------------------------------------------------------------------- - DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint); +/** + Returns the magnitude part of a topic - // walk the fingerprint - for (unsigned int i=0; i<20; i++) { - bytearray[i] = strtol(fingerprint + 3*i, NULL, 16); + @param topic the full MQTT topic + @return String object with the magnitude part. +*/ +String mqttMagnitude(char * topic) { + + String pattern = _mqtt_topic + _mqtt_setter; + int position = pattern.indexOf("#"); + if (position == -1) return String(); + String start = pattern.substring(0, position); + String end = pattern.substring(position + 1); + + String magnitude = String(topic); + if (magnitude.startsWith(start) && magnitude.endsWith(end)) { + magnitude.replace(start, ""); + magnitude.replace(end, ""); + } else { + magnitude = String(); } - return true; + return magnitude; } -#else +/** + Returns a full MQTT topic from the magnitude -bool mqttFormatFP(const char * fingerprint, char * destination) { + @param magnitude the magnitude part of the topic. + @param is_set whether to build a command topic (true) + or a state topic (false). + @return String full MQTT topic. +*/ +String mqttTopic(const char * magnitude, bool is_set) { + String output = _mqtt_topic; + output.replace("#", magnitude); + output += is_set ? _mqtt_setter : _mqtt_getter; + return output; +} - // check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59) - if (strlen(fingerprint) != 59) return false; +/** + Returns a full MQTT topic from the magnitude - DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint); + @param magnitude the magnitude part of the topic. + @param index index of the magnitude when more than one such magnitudes. + @param is_set whether to build a command topic (true) + or a state topic (false). + @return String full MQTT topic. +*/ +String mqttTopic(const char * magnitude, unsigned int index, bool is_set) { + char buffer[strlen(magnitude)+5]; + snprintf_P(buffer, sizeof(buffer), PSTR("%s/%d"), magnitude, index); + return mqttTopic(buffer, is_set); +} - // copy it - strncpy(destination, fingerprint, 59); +// ----------------------------------------------------------------------------- - // walk the fingerprint replacing ':' for ' ' - for (unsigned char i = 0; i<59; i++) { - if (destination[i] == ':') destination[i] = ' '; +void mqttSendRaw(const char * topic, const char * message, bool retain) { + + if (_mqtt.connected()) { + #if MQTT_USE_ASYNC + unsigned int packetId = _mqtt.publish(topic, _mqtt_qos, retain, message); + DEBUG_MSG_P(PSTR("[MQTT] Sending %s => %s (PID %d)\n"), topic, message, packetId); + #else + _mqtt.publish(topic, message, retain); + DEBUG_MSG_P(PSTR("[MQTT] Sending %s => %s\n"), topic, message); + #endif } +} - return true; +void mqttSendRaw(const char * topic, const char * message) { + mqttSendRaw (topic, message, _mqtt_retain); } -#endif +void mqttSend(const char * topic, const char * message, bool force, bool retain) { -void mqttEnabled(bool status) { - _mqtt_enabled = status; - setSetting("mqttEnabled", status ? 1 : 0); -} + bool useJson = force ? false : _mqtt_use_json; -bool mqttEnabled() { - return _mqtt_enabled; -} + // Equeue message + if (useJson) { -void mqttConnect() { + // Set default queue topic + mqttQueueTopic(MQTT_TOPIC_JSON); - // Do not connect if disabled - if (!_mqtt_enabled) return; + // Enqueue new message + mqttEnqueue(topic, message); - // Do not connect if already connected - if (_mqtt.connected()) return; + // Reset flush timer + _mqtt_flush_ticker.once_ms(MQTT_USE_JSON_DELAY, mqttFlush); - // Check reconnect interval - static unsigned long last = 0; - if (millis() - last < _mqtt_reconnect_delay) return; - last = millis(); + // Send it right away + } else { + mqttSendRaw(mqttTopic(topic, false).c_str(), message, retain); - // Increase the reconnect delay - _mqtt_reconnect_delay += MQTT_RECONNECT_DELAY_STEP; - if (_mqtt_reconnect_delay > MQTT_RECONNECT_DELAY_MAX) { - _mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MAX; } - char * host = strdup(getSetting("mqttServer", MQTT_SERVER).c_str()); - if (strlen(host) == 0) return; - unsigned int port = getSetting("mqttPort", MQTT_PORT).toInt(); +} - if (_mqtt_user) free(_mqtt_user); - if (_mqtt_pass) free(_mqtt_pass); - if (_mqtt_will) free(_mqtt_will); +void mqttSend(const char * topic, const char * message, bool force) { + mqttSend(topic, message, force, _mqtt_retain); +} - _mqtt_user = strdup(getSetting("mqttUser", MQTT_USER).c_str()); - _mqtt_pass = strdup(getSetting("mqttPassword", MQTT_PASS).c_str()); - _mqtt_will = strdup((_mqtt_topic + MQTT_TOPIC_STATUS).c_str()); +void mqttSend(const char * topic, const char * message) { + mqttSend(topic, message, false); +} - DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%d\n"), host, port); +void mqttSend(const char * topic, unsigned int index, const char * message, bool force, bool retain) { + char buffer[strlen(topic)+5]; + snprintf_P(buffer, sizeof(buffer), PSTR("%s/%d"), topic, index); + mqttSend(buffer, message, force, retain); +} - #if MQTT_USE_ASYNC +void mqttSend(const char * topic, unsigned int index, const char * message, bool force) { + mqttSend(topic, index, message, force, _mqtt_retain); +} - _mqtt.setServer(host, port); - _mqtt.setKeepAlive(_mqtt_keepalive).setCleanSession(false); - _mqtt.setWill(_mqtt_will, _mqtt_qos, _mqtt_retain, "0"); - if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) { - DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user); - _mqtt.setCredentials(_mqtt_user, _mqtt_pass); - } +void mqttSend(const char * topic, unsigned int index, const char * message) { + mqttSend(topic, index, message, false); +} - #if ASYNC_TCP_SSL_ENABLED +// ----------------------------------------------------------------------------- - bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1; - _mqtt.setSecure(secure); - if (secure) { - DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n")); - unsigned char fp[20] = {0}; - if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) { - _mqtt.addServerFingerprint(fp); - } else { - DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n")); - } +unsigned char _mqttBuildTree(JsonObject& root, char parent) { + + unsigned char count = 0; + + // Add enqueued messages + for (unsigned char i=0; i<_mqtt_queue.size(); i++) { + mqtt_message_t element = _mqtt_queue[i]; + if (element.parent == parent) { + ++count; + JsonObject& elements = root.createNestedObject(element.topic); + unsigned char num = _mqttBuildTree(elements, i); + if (0 == num) { + root.set(element.topic, element.message); } + } + } - #endif // ASYNC_TCP_SSL_ENABLED + return count; - DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will); - DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos); - DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0); +} - _mqtt.connect(); +void mqttFlush() { - #else // not MQTT_USE_ASYNC + if (!_mqtt.connected()) return; + if (_mqtt_queue.size() == 0) return; - bool response = true; + // Build tree recursively + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.createObject(); + _mqttBuildTree(root, 255); - #if ASYNC_TCP_SSL_ENABLED + // Add extra propeties + #if NTP_SUPPORT && MQTT_ENQUEUE_DATETIME + if (ntpSynced()) root[MQTT_TOPIC_TIME] = ntpDateTime(); + #endif + #if MQTT_ENQUEUE_MAC + root[MQTT_TOPIC_MAC] = WiFi.macAddress(); + #endif + #if MQTT_ENQUEUE_HOSTNAME + root[MQTT_TOPIC_HOSTNAME] = getSetting("hostname"); + #endif + #if MQTT_ENQUEUE_IP + root[MQTT_TOPIC_IP] = getIP(); + #endif + #if MQTT_ENQUEUE_MESSAGE_ID + root[MQTT_TOPIC_MESSAGE_ID] = _mqttNextMessageId(); + #endif - bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1; - if (secure) { - DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n")); - if (_mqtt_client_secure.connect(host, port)) { - char fp[60] = {0}; - if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) { - if (_mqtt_client_secure.verify(fp, host)) { - _mqtt.setClient(_mqtt_client_secure); - } else { - DEBUG_MSG_P(PSTR("[MQTT] Invalid fingerprint\n")); - response = false; - } - _mqtt_client_secure.stop(); - yield(); - } else { - DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n")); - response = false; - } - } else { - DEBUG_MSG_P(PSTR("[MQTT] Client connection failed\n")); - response = false; - } + // Send + String output; + root.printTo(output); + jsonBuffer.clear(); - } else { - _mqtt.setClient(_mqtt_client); - } + mqttSendRaw(_mqtt_topic_json.c_str(), output.c_str(), false); - #else // not ASYNC_TCP_SSL_ENABLED + // Clear queue + for (unsigned char i = 0; i < _mqtt_queue.size(); i++) { + mqtt_message_t element = _mqtt_queue[i]; + free(element.topic); + if (element.message) { + free(element.message); + } + } + _mqtt_queue.clear(); - _mqtt.setClient(_mqtt_client); +} - #endif // ASYNC_TCP_SSL_ENABLED +void mqttQueueTopic(const char * topic) { + String t = mqttTopic(topic, false); + if (!t.equals(_mqtt_topic_json)) { + mqttFlush(); + _mqtt_topic_json = t; + } +} - if (response) { +int8_t mqttEnqueue(const char * topic, const char * message, unsigned char parent) { - _mqtt.setServer(host, port); + // Queue is not meant to send message "offline" + // We must prevent the queue does not get full while offline + if (!_mqtt.connected()) return -1; - if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) { - DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user); - response = _mqtt.connect(getIdentifier().c_str(), _mqtt_user, _mqtt_pass, _mqtt_will, _mqtt_qos, _mqtt_retain, "0"); - } else { - response = _mqtt.connect(getIdentifier().c_str(), _mqtt_will, _mqtt_qos, _mqtt_retain, "0"); - } + // Force flusing the queue if the MQTT_QUEUE_MAX_SIZE has been reached + if (_mqtt_queue.size() >= MQTT_QUEUE_MAX_SIZE) mqttFlush(); - DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will); - DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos); - DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0); + int8_t index = _mqtt_queue.size(); - } + // Enqueue new message + mqtt_message_t element; + element.parent = parent; + element.topic = strdup(topic); + if (NULL != message) { + element.message = strdup(message); + } + _mqtt_queue.push_back(element); - if (response) { - _mqttOnConnect(); - } else { - DEBUG_MSG_P(PSTR("[MQTT] Connection failed\n")); - } + return index; - #endif // MQTT_USE_ASYNC +} - free(host); +int8_t mqttEnqueue(const char * topic, const char * message) { + return mqttEnqueue(topic, message, 255); +} + +// ----------------------------------------------------------------------------- +void mqttSubscribeRaw(const char * topic) { + if (_mqtt.connected() && (strlen(topic) > 0)) { + #if MQTT_USE_ASYNC + unsigned int packetId = _mqtt.subscribe(topic, _mqtt_qos); + DEBUG_MSG_P(PSTR("[MQTT] Subscribing to %s (PID %d)\n"), topic, packetId); + #else + _mqtt.subscribe(topic, _mqtt_qos); + DEBUG_MSG_P(PSTR("[MQTT] Subscribing to %s\n"), topic); + #endif + } } -void mqttConfigure() { +void mqttSubscribe(const char * topic) { + mqttSubscribeRaw(mqttTopic(topic, true).c_str()); +} - // Replace identifier - _mqtt_topic = getSetting("mqttTopic", MQTT_TOPIC); - _mqtt_topic.replace("{identifier}", getSetting("hostname")); - if (!_mqtt_topic.endsWith("/")) _mqtt_topic = _mqtt_topic + "/"; +void mqttUnsubscribeRaw(const char * topic) { + if (_mqtt.connected() && (strlen(topic) > 0)) { + #if MQTT_USE_ASYNC + unsigned int packetId = _mqtt.unsubscribe(topic); + DEBUG_MSG_P(PSTR("[MQTT] Unsubscribing to %s (PID %d)\n"), topic, packetId); + #else + _mqtt.unsubscribe(topic); + DEBUG_MSG_P(PSTR("[MQTT] Unsubscribing to %s\n"), topic); + #endif + } +} - // Getters and setters - _mqtt_setter = getSetting("mqttSetter", MQTT_USE_SETTER); - _mqtt_getter = getSetting("mqttGetter", MQTT_USE_GETTER); - _mqtt_forward = !_mqtt_getter.equals(_mqtt_setter); +void mqttUnsubscribe(const char * topic) { + mqttUnsubscribeRaw(mqttTopic(topic, true).c_str()); +} - // MQTT options - _mqtt_qos = getSetting("mqttQoS", MQTT_QOS).toInt(); - _mqtt_retain = getSetting("mqttRetain", MQTT_RETAIN).toInt() == 1; - _mqtt_keepalive = getSetting("mqttKeep", MQTT_KEEPALIVE).toInt(); +// ----------------------------------------------------------------------------- - // Enable - if (getSetting("mqttServer", MQTT_SERVER).length() == 0) { - mqttEnabled(false); - } else { - _mqtt_enabled = getSetting("mqttEnabled", MQTT_ENABLED).toInt() == 1; +void mqttEnabled(bool status) { + _mqtt_enabled = status; + setSetting("mqttEnabled", status ? 1 : 0); +} + +bool mqttEnabled() { + return _mqtt_enabled; +} + +bool mqttConnected() { + return _mqtt.connected(); +} + +void mqttDisconnect() { + if (_mqtt.connected()) { + DEBUG_MSG_P(PSTR("[MQTT] Disconnecting\n")); + _mqtt.disconnect(); } - _mqtt_use_json = (getSetting("mqttUseJson", MQTT_USE_JSON).toInt() == 1); +} - _mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN; +bool mqttForward() { + return _mqtt_forward; +} +void mqttRegister(mqtt_callback_f callback) { + _mqtt_callbacks.push_back(callback); } void mqttSetBroker(IPAddress ip, unsigned int port) { @@ -527,10 +739,24 @@ void mqttSetBrokerIfNone(IPAddress ip, unsigned int port) { if (!hasSetting("mqttServer")) mqttSetBroker(ip, port); } +void mqttReset() { + _mqttConfigure(); + mqttDisconnect(); +} + +// ----------------------------------------------------------------------------- +// Initialization +// ----------------------------------------------------------------------------- + void mqttSetup() { - DEBUG_MSG_P(PSTR("[MQTT] MQTT_USE_ASYNC = %d\n"), MQTT_USE_ASYNC); - DEBUG_MSG_P(PSTR("[MQTT] MQTT_AUTOCONNECT = %d\n"), MQTT_AUTOCONNECT); + _mqttBackwards(); + + DEBUG_MSG_P(PSTR("[MQTT] Async %s, SSL %s, Autoconnect %s\n"), + MQTT_USE_ASYNC ? "ENABLED" : "DISABLED", + ASYNC_TCP_SSL_ENABLED ? "ENABLED" : "DISABLED", + MQTT_AUTOCONNECT ? "ENABLED" : "DISABLED" + ); #if MQTT_USE_ASYNC @@ -572,21 +798,28 @@ void mqttSetup() { #else // not MQTT_USE_ASYNC - DEBUG_MSG_P(PSTR("[MQTT] Using SYNC MQTT library\n")); - _mqtt.setCallback([](char* topic, byte* payload, unsigned int length) { _mqttOnMessage(topic, (char *) payload, length); }); #endif // MQTT_USE_ASYNC - mqttConfigure(); + _mqttConfigure(); mqttRegister(_mqttCallback); #if WEB_SUPPORT wsOnSendRegister(_mqttWebSocketOnSend); + wsOnAfterParseRegister(_mqttConfigure); + wsOnReceiveRegister(_mqttWebSocketOnReceive); #endif + #if TERMINAL_SUPPORT + _mqttInitCommands(); + #endif + + // Register loop + espurnaRegisterLoop(mqttLoop); + } void mqttLoop() { @@ -595,7 +828,7 @@ void mqttLoop() { #if MQTT_USE_ASYNC - mqttConnect(); + _mqttConnect(); #else // not MQTT_USE_ASYNC @@ -610,7 +843,7 @@ void mqttLoop() { _mqtt_connected = false; } - mqttConnect(); + _mqttConnect(); } diff --git a/code/espurna/netbios.ino b/code/espurna/netbios.ino index 478b81f9..418a1843 100644 --- a/code/espurna/netbios.ino +++ b/code/espurna/netbios.ino @@ -2,7 +2,7 @@ NETBIOS MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez */ diff --git a/code/espurna/nofuss.ino b/code/espurna/nofuss.ino index 6350b82e..c9247986 100644 --- a/code/espurna/nofuss.ino +++ b/code/espurna/nofuss.ino @@ -2,7 +2,7 @@ NOFUSS MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -18,15 +18,27 @@ bool _nofussEnabled = false; // NOFUSS // ----------------------------------------------------------------------------- +#if WEB_SUPPORT + +bool _nofussWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "nofuss", 6) == 0); +} + void _nofussWebSocketOnSend(JsonObject& root) { root["nofussVisible"] = 1; root["nofussEnabled"] = getSetting("nofussEnabled", NOFUSS_ENABLED).toInt() == 1; root["nofussServer"] = getSetting("nofussServer", NOFUSS_SERVER); } +#endif + void _nofussConfigure() { String nofussServer = getSetting("nofussServer", NOFUSS_SERVER); + #if MDNS_CLIENT_SUPPORT + nofussServer = mdnsResolve(nofussServer); + #endif + if (nofussServer.length() == 0) { setSetting("nofussEnabled", 0); _nofussEnabled = false; @@ -58,6 +70,19 @@ void _nofussConfigure() { } +#if TERMINAL_SUPPORT + +void _nofussInitCommands() { + + settingsRegisterCommand(F("NOFUSS"), [](Embedis* e) { + DEBUG_MSG_P(PSTR("+OK\n")); + nofussRun(); + }); + +} + +#endif // TERMINAL_SUPPORT + // ----------------------------------------------------------------------------- void nofussRun() { @@ -118,7 +143,7 @@ void nofussSetup() { #if WEB_SUPPORT wsSend_P(PSTR("{\"action\": \"reload\"}")); #endif - delay(100); + nice_delay(100); } if (code == NOFUSS_END) { @@ -130,8 +155,16 @@ void nofussSetup() { #if WEB_SUPPORT wsOnSendRegister(_nofussWebSocketOnSend); wsOnAfterParseRegister(_nofussConfigure); + wsOnReceiveRegister(_nofussWebSocketOnReceive); + #endif + + #if TERMINAL_SUPPORT + _nofussInitCommands(); #endif + // Register loop + espurnaRegisterLoop(nofussLoop); + } void nofussLoop() { diff --git a/code/espurna/ntp.ino b/code/espurna/ntp.ino index 0bc30f88..2a8134a6 100644 --- a/code/espurna/ntp.ino +++ b/code/espurna/ntp.ino @@ -2,7 +2,7 @@ NTP MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -13,64 +13,150 @@ Copyright (C) 2016-2017 by Xose Pérez #include #include -WiFiEventHandler _ntp_wifi_onSTA; -Ticker _ntp_delay; +unsigned long _ntp_start = 0; +bool _ntp_update = false; +bool _ntp_configure = false; // ----------------------------------------------------------------------------- // NTP // ----------------------------------------------------------------------------- +#if WEB_SUPPORT + +bool _ntpWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "ntp", 3) == 0); +} + void _ntpWebSocketOnSend(JsonObject& root) { - root["time"] = ntpDateTime(); root["ntpVisible"] = 1; - root["ntpStatus"] = ntpConnected(); - root["ntpServer1"] = getSetting("ntpServer1", NTP_SERVER); - root["ntpServer2"] = getSetting("ntpServer2"); - root["ntpServer3"] = getSetting("ntpServer3"); + root["ntpStatus"] = (timeStatus() == timeSet); + root["ntpServer"] = getSetting("ntpServer", NTP_SERVER); root["ntpOffset"] = getSetting("ntpOffset", NTP_TIME_OFFSET).toInt(); root["ntpDST"] = getSetting("ntpDST", NTP_DAY_LIGHT).toInt() == 1; + root["ntpRegion"] = getSetting("ntpRegion", NTP_DST_REGION).toInt(); + if (ntpSynced()) root["now"] = now(); +} + +#endif + +void _ntpStart() { + + _ntp_start = 0; + + NTP.begin(getSetting("ntpServer", NTP_SERVER)); + NTP.setInterval(NTP_SYNC_INTERVAL, NTP_UPDATE_INTERVAL); + NTP.setNTPTimeout(NTP_TIMEOUT); + _ntpConfigure(); + +} + +void _ntpConfigure() { + + _ntp_configure = false; + + int offset = getSetting("ntpOffset", NTP_TIME_OFFSET).toInt(); + int sign = offset > 0 ? 1 : -1; + offset = abs(offset); + int tz_hours = sign * (offset / 60); + int tz_minutes = sign * (offset % 60); + if (NTP.getTimeZone() != tz_hours || NTP.getTimeZoneMinutes() != tz_minutes) { + NTP.setTimeZone(tz_hours, tz_minutes); + _ntp_update = true; + } + + bool daylight = getSetting("ntpDST", NTP_DAY_LIGHT).toInt() == 1; + if (NTP.getDayLight() != daylight) { + NTP.setDayLight(daylight); + _ntp_update = true; + } + + String server = getSetting("ntpServer", NTP_SERVER); + if (!NTP.getNtpServerName().equals(server)) { + NTP.setNtpServerName(server); + } + + uint8_t dst_region = getSetting("ntpRegion", NTP_DST_REGION).toInt(); + NTP.setDSTZone(dst_region); + } void _ntpUpdate() { + + _ntp_update = false; + #if WEB_SUPPORT wsSend(_ntpWebSocketOnSend); #endif - DEBUG_MSG_P(PSTR("[NTP] Time: %s\n"), (char *) ntpDateTime().c_str()); + + if (ntpSynced()) { + time_t t = now(); + DEBUG_MSG_P(PSTR("[NTP] UTC Time : %s\n"), (char *) ntpDateTime(ntpLocal2UTC(t)).c_str()); + DEBUG_MSG_P(PSTR("[NTP] Local Time: %s\n"), (char *) ntpDateTime(t).c_str()); + } + } -void _ntpConfigure() { - NTP.begin( - getSetting("ntpServer1", NTP_SERVER), - getSetting("ntpOffset", NTP_TIME_OFFSET).toInt(), - getSetting("ntpDST", NTP_DAY_LIGHT).toInt() == 1 - ); - if (getSetting("ntpServer2")) NTP.setNtpServerName(getSetting("ntpServer2"), 1); - if (getSetting("ntpServer3")) NTP.setNtpServerName(getSetting("ntpServer3"), 2); - NTP.setInterval(NTP_UPDATE_INTERVAL); +void _ntpLoop() { + + if (0 < _ntp_start && _ntp_start < millis()) _ntpStart(); + if (_ntp_configure) _ntpConfigure(); + if (_ntp_update) _ntpUpdate(); + + now(); + + #if BROKER_SUPPORT + static unsigned char last_minute = 60; + if (ntpSynced() && (minute() != last_minute)) { + last_minute = minute(); + brokerPublish(MQTT_TOPIC_DATETIME, ntpDateTime().c_str()); + } + #endif + +} + +void _ntpBackwards() { + moveSetting("ntpServer1", "ntpServer"); + delSetting("ntpServer2"); + delSetting("ntpServer3"); + int offset = getSetting("ntpOffset", NTP_TIME_OFFSET).toInt(); + if (-30 < offset && offset < 30) { + offset *= 60; + setSetting("ntpOffset", offset); + } } // ----------------------------------------------------------------------------- -bool ntpConnected() { - return (timeStatus() == timeSet); +bool ntpSynced() { + return (year() > 2017); } -String ntpDateTime() { - if (!ntpConnected()) return String("Not set"); - String value = NTP.getTimeDateString(); - int hour = value.substring(0, 2).toInt(); - int minute = value.substring(3, 5).toInt(); - int second = value.substring(6, 8).toInt(); - int day = value.substring(9, 11).toInt(); - int month = value.substring(12, 14).toInt(); - int year = value.substring(15, 19).toInt(); +String ntpDateTime(time_t t) { char buffer[20]; - snprintf_P(buffer, sizeof(buffer), PSTR("%04d-%02d-%02d %02d:%02d:%02d"), year, month, day, hour, minute, second); + snprintf_P(buffer, sizeof(buffer), + PSTR("%04d-%02d-%02d %02d:%02d:%02d"), + year(t), month(t), day(t), hour(t), minute(t), second(t) + ); return String(buffer); } +String ntpDateTime() { + if (ntpSynced()) return ntpDateTime(now()); + return String(); +} + +time_t ntpLocal2UTC(time_t local) { + int offset = getSetting("ntpOffset", NTP_TIME_OFFSET).toInt(); + if (NTP.isSummerTime()) offset += 60; + return local - offset * 60; +} + +// ----------------------------------------------------------------------------- + void ntpSetup() { + _ntpBackwards(); + NTP.onNTPSyncEvent([](NTPSyncEvent_t error) { if (error) { #if WEB_SUPPORT @@ -82,23 +168,23 @@ void ntpSetup() { DEBUG_MSG_P(PSTR("[NTP] Error: Invalid NTP server address\n")); } } else { - _ntp_delay.once_ms(100, _ntpUpdate); + _ntp_update = true; } }); - _ntp_wifi_onSTA = WiFi.onStationModeGotIP([](WiFiEventStationModeGotIP ipInfo) { - _ntpConfigure(); + wifiRegister([](justwifi_messages_t code, char * parameter) { + if (code == MESSAGE_CONNECTED) _ntp_start = millis() + NTP_START_DELAY; }); #if WEB_SUPPORT wsOnSendRegister(_ntpWebSocketOnSend); - wsOnAfterParseRegister(_ntpConfigure); + wsOnReceiveRegister(_ntpWebSocketOnReceive); + wsOnAfterParseRegister([]() { _ntp_configure = true; }); #endif -} + // Register loop + espurnaRegisterLoop(_ntpLoop); -void ntpLoop() { - now(); } #endif // NTP_SUPPORT diff --git a/code/espurna/ota.ino b/code/espurna/ota.ino index 457fd576..4443431a 100644 --- a/code/espurna/ota.ino +++ b/code/espurna/ota.ino @@ -2,40 +2,236 @@ OTA MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ #include "ArduinoOTA.h" // ----------------------------------------------------------------------------- -// OTA +// Arduino OTA // ----------------------------------------------------------------------------- void _otaConfigure() { ArduinoOTA.setPort(OTA_PORT); ArduinoOTA.setHostname(getSetting("hostname").c_str()); - ArduinoOTA.setPassword(getSetting("adminPass", ADMIN_PASS).c_str()); + #if USE_PASSWORD + ArduinoOTA.setPassword(getSetting("adminPass", ADMIN_PASS).c_str()); + #endif +} + +void _otaLoop() { + ArduinoOTA.handle(); +} + +// ----------------------------------------------------------------------------- +// Terminal OTA +// ----------------------------------------------------------------------------- + +#if TERMINAL_SUPPORT + +#include +AsyncClient * _ota_client; +char * _ota_host; +char * _ota_url; +unsigned int _ota_port = 80; +unsigned long _ota_size = 0; + +const char OTA_REQUEST_TEMPLATE[] PROGMEM = + "GET %s HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: ESPurna\r\n" + "Connection: close\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 0\r\n\r\n\r\n"; + + +void _otaFrom(const char * host, unsigned int port, const char * url) { + + if (_ota_host) free(_ota_host); + if (_ota_url) free(_ota_url); + _ota_host = strdup(host); + _ota_url = strdup(url); + _ota_port = port; + _ota_size = 0; + + if (_ota_client == NULL) { + _ota_client = new AsyncClient(); + } + + _ota_client->onDisconnect([](void *s, AsyncClient *c) { + + DEBUG_MSG_P(PSTR("\n")); + + if (Update.end(true)){ + DEBUG_MSG_P(PSTR("[OTA] Success: %u bytes\n"), _ota_size); + deferredReset(100, CUSTOM_RESET_OTA); + } else { + #ifdef DEBUG_PORT + Update.printError(DEBUG_PORT); + #endif + eepromRotate(true); + } + + DEBUG_MSG_P(PSTR("[OTA] Disconnected\n")); + + _ota_client->free(); + delete _ota_client; + _ota_client = NULL; + free(_ota_host); + _ota_host = NULL; + free(_ota_url); + _ota_url = NULL; + + }, 0); + + _ota_client->onTimeout([](void *s, AsyncClient *c, uint32_t time) { + _ota_client->close(true); + }, 0); + + _ota_client->onData([](void * arg, AsyncClient * c, void * data, size_t len) { + + char * p = (char *) data; + + if (_ota_size == 0) { + + Update.runAsync(true); + if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) { + #ifdef DEBUG_PORT + Update.printError(DEBUG_PORT); + #endif + } + + p = strstr((char *)data, "\r\n\r\n") + 4; + len = len - (p - (char *) data); + + } + + if (!Update.hasError()) { + if (Update.write((uint8_t *) p, len) != len) { + #ifdef DEBUG_PORT + Update.printError(DEBUG_PORT); + #endif + } + } + + _ota_size += len; + DEBUG_MSG_P(PSTR("[OTA] Progress: %u bytes\r"), _ota_size); + + + }, NULL); + + _ota_client->onConnect([](void * arg, AsyncClient * client) { + + #if ASYNC_TCP_SSL_ENABLED + if (443 == _ota_port) { + uint8_t fp[20] = {0}; + sslFingerPrintArray(getSetting("otafp", OTA_GITHUB_FP).c_str(), fp); + SSL * ssl = _ota_client->getSSL(); + if (ssl_match_fingerprint(ssl, fp) != SSL_OK) { + DEBUG_MSG_P(PSTR("[OTA] Warning: certificate doesn't match\n")); + } + } + #endif + + // Disabling EEPROM rotation to prevent writing to EEPROM after the upgrade + eepromRotate(false); + + DEBUG_MSG_P(PSTR("[OTA] Downloading %s\n"), _ota_url); + char buffer[strlen_P(OTA_REQUEST_TEMPLATE) + strlen(_ota_url) + strlen(_ota_host)]; + snprintf_P(buffer, sizeof(buffer), OTA_REQUEST_TEMPLATE, _ota_url, _ota_host); + client->write(buffer); + + }, NULL); + + #if ASYNC_TCP_SSL_ENABLED + bool connected = _ota_client->connect(host, port, 443 == port); + #else + bool connected = _ota_client->connect(host, port); + #endif + + if (!connected) { + DEBUG_MSG_P(PSTR("[OTA] Connection failed\n")); + _ota_client->close(true); + } + +} + +void _otaFrom(String url) { + + // Port from protocol + unsigned int port = 80; + if (url.startsWith("https://")) port = 443; + url = url.substring(url.indexOf("/") + 2); + + // Get host + String host = url.substring(0, url.indexOf("/")); + + // Explicit port + int p = host.indexOf(":"); + if (p > 0) { + port = host.substring(p + 1).toInt(); + host = host.substring(0, p); + } + + // Get URL + String uri = url.substring(url.indexOf("/")); + + _otaFrom(host.c_str(), port, uri.c_str()); + +} + +void _otaInitCommands() { + + settingsRegisterCommand(F("OTA"), [](Embedis* e) { + if (e->argc < 2) { + DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); + } else { + DEBUG_MSG_P(PSTR("+OK\n")); + String url = String(e->argv[1]); + _otaFrom(url); + } + }); + } +#endif // TERMINAL_SUPPORT + // ----------------------------------------------------------------------------- void otaSetup() { _otaConfigure(); + #if WEB_SUPPORT wsOnAfterParseRegister(_otaConfigure); #endif + #if TERMINAL_SUPPORT + _otaInitCommands(); + #endif + + // Register loop + espurnaRegisterLoop(_otaLoop); + + // ------------------------------------------------------------------------- + ArduinoOTA.onStart([]() { + + // Disabling EEPROM rotation to prevent writing to EEPROM after the upgrade + eepromRotate(false); + DEBUG_MSG_P(PSTR("[OTA] Start\n")); + #if WEB_SUPPORT wsSend_P(PSTR("{\"message\": 2}")); #endif + }); ArduinoOTA.onEnd([]() { - DEBUG_MSG_P(PSTR("\n[OTA] End\n")); + DEBUG_MSG_P(PSTR("\n")); + DEBUG_MSG_P(PSTR("[OTA] Done, restarting...\n")); #if WEB_SUPPORT wsSend_P(PSTR("{\"action\": \"reload\"}")); #endif @@ -43,7 +239,7 @@ void otaSetup() { }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { - DEBUG_MSG_P(PSTR("[OTA] Progress: %u%%%%\r"), (progress / (total / 100))); + DEBUG_MSG_P(PSTR("[OTA] Progress: %u%%\r"), (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { @@ -55,12 +251,9 @@ void otaSetup() { else if (error == OTA_RECEIVE_ERROR) DEBUG_MSG_P(PSTR("Receive Failed\n")); else if (error == OTA_END_ERROR) DEBUG_MSG_P(PSTR("End Failed\n")); #endif + eepromRotate(true); }); ArduinoOTA.begin(); } - -void otaLoop() { - ArduinoOTA.handle(); -} diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino index 5ed1bc0f..1c361a60 100644 --- a/code/espurna/relay.ino +++ b/code/espurna/relay.ino @@ -2,11 +2,11 @@ RELAY MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ -#include +#include #include #include #include @@ -17,12 +17,12 @@ typedef struct { // Configuration variables unsigned char pin; // GPIO pin for the relay - unsigned char type; // RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE or RELAY_TYPE_LATCHED + unsigned char type; // RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE, RELAY_TYPE_LATCHED or RELAY_TYPE_LATCHED_INVERSE unsigned char reset_pin; // GPIO to reset the relay if RELAY_TYPE_LATCHED - unsigned char pulse; // RELAY_PULSE_NONE, RELAY_PULSE_OFF or RELAY_PULSE_ON - unsigned long pulse_ms; // Pulse length in millis unsigned long delay_on; // Delay to turn relay ON unsigned long delay_off; // Delay to turn relay OFF + unsigned char pulse; // RELAY_PULSE_NONE, RELAY_PULSE_OFF or RELAY_PULSE_ON + unsigned long pulse_ms; // Pulse length in millis // Status variables @@ -77,9 +77,40 @@ void _relayProviderStatus(unsigned char id, bool status) { #endif + #if RELAY_PROVIDER == RELAY_PROVIDER_STM + Serial.flush(); + Serial.write(0xA0); + Serial.write(id + 1); + Serial.write(status); + Serial.write(0xA1 + status + id); + Serial.flush(); + #endif + #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT - lightState(status); + + // If the number of relays matches the number of light channels + // assume each relay controls one channel. + // If the number of relays is the number of channels plus 1 + // assume the first one controls all the channels and + // the rest one channel each. + // Otherwise every relay controls all channels. + // TODO: this won't work with a mixed of dummy and real relays + // but this option is not allowed atm (YANGNI) + if (_relays.size() == lightChannels()) { + lightState(id, status); + lightState(true); + } else if (_relays.size() == lightChannels() + 1) { + if (id == 0) { + lightState(status); + } else { + lightState(id-1, status); + } + } else { + lightState(status); + } + lightUpdate(true, true); + #endif #if RELAY_PROVIDER == RELAY_PROVIDER_RELAY @@ -87,28 +118,99 @@ void _relayProviderStatus(unsigned char id, bool status) { digitalWrite(_relays[id].pin, status); } else if (_relays[id].type == RELAY_TYPE_INVERSE) { digitalWrite(_relays[id].pin, !status); - } else if (_relays[id].type == RELAY_TYPE_LATCHED) { - digitalWrite(_relays[id].pin, LOW); - digitalWrite(_relays[id].reset_pin, LOW); + } else if (_relays[id].type == RELAY_TYPE_LATCHED || _relays[id].type == RELAY_TYPE_LATCHED_INVERSE) { + bool pulse = RELAY_TYPE_LATCHED ? HIGH : LOW; + digitalWrite(_relays[id].pin, !pulse); + digitalWrite(_relays[id].reset_pin, !pulse); if (status) { - digitalWrite(_relays[id].pin, HIGH); + digitalWrite(_relays[id].pin, pulse); } else { - digitalWrite(_relays[id].reset_pin, HIGH); + digitalWrite(_relays[id].reset_pin, pulse); } - delay(RELAY_LATCHING_PULSE); - digitalWrite(_relays[id].pin, LOW); - digitalWrite(_relays[id].reset_pin, LOW); + nice_delay(RELAY_LATCHING_PULSE); + digitalWrite(_relays[id].pin, !pulse); + digitalWrite(_relays[id].reset_pin, !pulse); } #endif } +/** + * Walks the relay vector processing only those relays + * that have to change to the requested mode + * @bool mode Requested mode + */ +void _relayProcess(bool mode) { + + unsigned long current_time = millis(); + + for (unsigned char id = 0; id < _relays.size(); id++) { + + bool target = _relays[id].target_status; + + // Only process the relays we have to change + if (target == _relays[id].current_status) continue; + + // Only process the relays we have change to the requested mode + if (target != mode) continue; + + // Only process if the change_time has arrived + if (current_time < _relays[id].change_time) continue; + + DEBUG_MSG_P(PSTR("[RELAY] #%d set to %s\n"), id, target ? "ON" : "OFF"); + + // Call the provider to perform the action + _relayProviderStatus(id, target); + + // Send to Broker + #if BROKER_SUPPORT + brokerPublish(MQTT_TOPIC_RELAY, id, target ? "1" : "0"); + #endif + + // Send MQTT + #if MQTT_SUPPORT + relayMQTT(id); + #endif + + if (!_relayRecursive) { + relayPulse(id); + _relaySaveTicker.once_ms(RELAY_SAVE_DELAY, relaySave); + #if WEB_SUPPORT + wsSend(_relayWebSocketUpdate); + #endif + } + + #if DOMOTICZ_SUPPORT + domoticzSendRelay(id); + #endif + + #if INFLUXDB_SUPPORT + relayInfluxDB(id); + #endif + + #if THINGSPEAK_SUPPORT + tspkEnqueueRelay(id, target); + tspkFlush(); + #endif + + // Flag relay-based LEDs to update status + ledUpdate(true); + + _relays[id].report = false; + _relays[id].group_report = false; + + } + +} + // ----------------------------------------------------------------------------- // RELAY // ----------------------------------------------------------------------------- void relayPulse(unsigned char id) { + _relays[id].pulseTicker.detach(); + byte mode = _relays[id].pulse; if (mode == RELAY_PULSE_NONE) return; unsigned long ms = _relays[id].pulse_ms; @@ -117,10 +219,12 @@ void relayPulse(unsigned char id) { bool status = relayStatus(id); bool pulseStatus = (mode == RELAY_PULSE_ON); - if (pulseStatus == status) { - _relays[id].pulseTicker.detach(); - } else { + if (pulseStatus != status) { + DEBUG_MSG_P(PSTR("[RELAY] Scheduling relay #%d back in %lums (pulse)\n"), id, ms); _relays[id].pulseTicker.once_ms(ms, relayToggle, id); + // Reconfigure after dynamic pulse + _relays[id].pulse = getSetting("relayPulse", id, RELAY_PULSE_MODE).toInt(); + _relays[id].pulse_ms = 1000 * getSetting("relayTime", id, RELAY_PULSE_MODE).toFloat(); } } @@ -146,6 +250,9 @@ bool relayStatus(unsigned char id, bool status, bool report, bool group_report) rfbStatus(id, status); #endif + // Update the pulse counter if the relay is already in the non-normal state (#454) + relayPulse(id); + } else { unsigned int current_time = millis(); @@ -253,9 +360,9 @@ void relaySave() { if (relayStatus(i)) mask += bit; bit += bit; } - EEPROM.write(EEPROM_RELAY_STATUS, mask); + EEPROMr.write(EEPROM_RELAY_STATUS, mask); DEBUG_MSG_P(PSTR("[RELAY] Saving mask: %d\n"), mask); - EEPROM.commit(); + EEPROMr.commit(); } void relayToggle(unsigned char id, bool report, bool group_report) { @@ -333,7 +440,7 @@ void _relayBoot() { bool trigger_save = false; // Get last statuses from EEPROM - unsigned char mask = EEPROM.read(EEPROM_RELAY_STATUS); + unsigned char mask = EEPROMr.read(EEPROM_RELAY_STATUS); DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %d\n"), mask); // Walk the relays @@ -345,7 +452,7 @@ void _relayBoot() { case RELAY_BOOT_SAME: status = ((mask & bit) == bit); break; - case RELAY_BOOT_TOOGLE: + case RELAY_BOOT_TOGGLE: status = ((mask & bit) != bit); mask ^= bit; trigger_save = true; @@ -360,26 +467,45 @@ void _relayBoot() { } _relays[i].current_status = !status; _relays[i].target_status = status; - _relays[i].change_time = millis(); + #if RELAY_PROVIDER == RELAY_PROVIDER_STM + _relays[i].change_time = millis() + 3000 + 1000 * i; + #else + _relays[i].change_time = millis(); + #endif bit <<= 1; } - // Save if there is any relay in the RELAY_BOOT_TOOGLE mode + // Save if there is any relay in the RELAY_BOOT_TOGGLE mode if (trigger_save) { - EEPROM.write(EEPROM_RELAY_STATUS, mask); - EEPROM.commit(); + EEPROMr.write(EEPROM_RELAY_STATUS, mask); + EEPROMr.commit(); } _relayRecursive = false; } +void _relayConfigure() { + for (unsigned int i=0; i<_relays.size(); i++) { + pinMode(_relays[i].pin, OUTPUT); + if (_relays[i].type == RELAY_TYPE_LATCHED || _relays[i].type == RELAY_TYPE_LATCHED_INVERSE) { + pinMode(_relays[i].reset_pin, OUTPUT); + } + _relays[i].pulse = getSetting("relayPulse", i, RELAY_PULSE_MODE).toInt(); + _relays[i].pulse_ms = 1000 * getSetting("relayTime", i, RELAY_PULSE_MODE).toFloat(); + } +} + //------------------------------------------------------------------------------ // WEBSOCKETS //------------------------------------------------------------------------------ #if WEB_SUPPORT +bool _relayWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "relay", 5) == 0); +} + void _relayWebSocketUpdate(JsonObject& root) { JsonArray& relay = root.createNestedArray("relayStatus"); for (unsigned char i=0; i= relayCount()) { + DEBUG_MSG_P(PSTR("[RELAY] Wrong relayID (%d)\n"), id); + return; + } + + unsigned long pulse = 1000 * String(payload).toFloat(); + if (0 == pulse) return; + + if (RELAY_PULSE_NONE != _relays[id].pulse) { + DEBUG_MSG_P(PSTR("[RELAY] Overriding relay #%d pulse settings\n"), id); + } + + _relays[id].pulse_ms = pulse; + _relays[id].pulse = relayStatus(id) ? RELAY_PULSE_ON : RELAY_PULSE_OFF; + relayToggle(id, true, false); + + return; + + } + + // magnitude is relay/# + if (t.startsWith(MQTT_TOPIC_RELAY)) { // Get relay ID unsigned int id = t.substring(strlen(MQTT_TOPIC_RELAY)+1).toInt(); if (id >= relayCount()) { DEBUG_MSG_P(PSTR("[RELAY] Wrong relayID (%d)\n"), id); - } else { - relayStatusWrap(id, value, false); + return; } - return; + // Get value + unsigned char value = relayParsePayload(payload); + if (value == 0xFF) return; + + relayStatusWrap(id, value, false); + return; } + // Check group topics for (unsigned int i=0; i < _relays.size(); i++) { @@ -629,6 +810,20 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo } + if (type == MQTT_DISCONNECT_EVENT) { + for (unsigned int i=0; i < _relays.size(); i++){ + int reaction = getSetting("relayOnDisc", i, 0).toInt(); + if (1 == reaction) { // switch relay OFF + DEBUG_MSG_P(PSTR("[RELAY] Reset relay (%d) due to MQTT disconnection\n"), i); + relayStatusWrap(i, false, false); + } else if(2 == reaction) { // switch relay ON + DEBUG_MSG_P(PSTR("[RELAY] Set relay (%d) due to MQTT disconnection\n"), i); + relayStatusWrap(i, true, false); + } + } + + } + } void relaySetupMQTT() { @@ -642,50 +837,99 @@ void relaySetupMQTT() { //------------------------------------------------------------------------------ #if INFLUXDB_SUPPORT + void relayInfluxDB(unsigned char id) { if (id >= _relays.size()) return; idbSend(MQTT_TOPIC_RELAY, id, relayStatus(id) ? "1" : "0"); } + #endif + +//------------------------------------------------------------------------------ +// Settings +//------------------------------------------------------------------------------ + +#if TERMINAL_SUPPORT + +void _relayInitCommands() { + + settingsRegisterCommand(F("RELAY"), [](Embedis* e) { + if (e->argc < 2) { + DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); + return; + } + int id = String(e->argv[1]).toInt(); + if (id >= relayCount()) { + DEBUG_MSG_P(PSTR("-ERROR: Wrong relayID (%d)\n"), id); + return; + } + + if (e->argc > 2) { + int value = String(e->argv[2]).toInt(); + if (value == 2) { + relayToggle(id); + } else { + relayStatus(id, value == 1); + } + } + DEBUG_MSG_P(PSTR("Status: %s\n"), _relays[id].target_status ? "true" : "false"); + if (_relays[id].pulse != RELAY_PULSE_NONE) { + DEBUG_MSG_P(PSTR("Pulse: %s\n"), (_relays[id].pulse == RELAY_PULSE_ON) ? "ON" : "OFF"); + DEBUG_MSG_P(PSTR("Pulse time: %d\n"), _relays[id].pulse_ms); + + } + DEBUG_MSG_P(PSTR("+OK\n")); + }); + +} + +#endif // TERMINAL_SUPPORT + //------------------------------------------------------------------------------ // Setup //------------------------------------------------------------------------------ +void _relayLoop() { + _relayProcess(false); + _relayProcess(true); +} + void relaySetup() { // Dummy relays for AI Light, Magic Home LED Controller, H801, // Sonoff Dual and Sonoff RF Bridge - #ifdef DUMMY_RELAY_COUNT - + #if DUMMY_RELAY_COUNT > 0 + unsigned int _delay_on[8] = {RELAY1_DELAY_ON, RELAY2_DELAY_ON, RELAY3_DELAY_ON, RELAY4_DELAY_ON, RELAY5_DELAY_ON, RELAY6_DELAY_ON, RELAY7_DELAY_ON, RELAY8_DELAY_ON}; + unsigned int _delay_off[8] = {RELAY1_DELAY_OFF, RELAY2_DELAY_OFF, RELAY3_DELAY_OFF, RELAY4_DELAY_OFF, RELAY5_DELAY_OFF, RELAY6_DELAY_OFF, RELAY7_DELAY_OFF, RELAY8_DELAY_OFF}; for (unsigned char i=0; i < DUMMY_RELAY_COUNT; i++) { - _relays.push_back((relay_t) {0, RELAY_TYPE_NORMAL}); + _relays.push_back((relay_t) {0, RELAY_TYPE_NORMAL,0,_delay_on[i], _delay_off[i]}); } #else - #ifdef RELAY1_PIN + #if RELAY1_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY1_PIN, RELAY1_TYPE, RELAY1_RESET_PIN, RELAY1_DELAY_ON, RELAY1_DELAY_OFF }); #endif - #ifdef RELAY2_PIN + #if RELAY2_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY2_PIN, RELAY2_TYPE, RELAY2_RESET_PIN, RELAY2_DELAY_ON, RELAY2_DELAY_OFF }); #endif - #ifdef RELAY3_PIN + #if RELAY3_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY3_PIN, RELAY3_TYPE, RELAY3_RESET_PIN, RELAY3_DELAY_ON, RELAY3_DELAY_OFF }); #endif - #ifdef RELAY4_PIN + #if RELAY4_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY4_PIN, RELAY4_TYPE, RELAY4_RESET_PIN, RELAY4_DELAY_ON, RELAY4_DELAY_OFF }); #endif - #ifdef RELAY5_PIN + #if RELAY5_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY5_PIN, RELAY5_TYPE, RELAY5_RESET_PIN, RELAY5_DELAY_ON, RELAY5_DELAY_OFF }); #endif - #ifdef RELAY6_PIN + #if RELAY6_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY6_PIN, RELAY6_TYPE, RELAY6_RESET_PIN, RELAY6_DELAY_ON, RELAY6_DELAY_OFF }); #endif - #ifdef RELAY7_PIN + #if RELAY7_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY7_PIN, RELAY7_TYPE, RELAY7_RESET_PIN, RELAY7_DELAY_ON, RELAY7_DELAY_OFF }); #endif - #ifdef RELAY8_PIN + #if RELAY8_PIN != GPIO_NONE _relays.push_back((relay_t) { RELAY8_PIN, RELAY8_TYPE, RELAY8_RESET_PIN, RELAY8_DELAY_ON, RELAY8_DELAY_OFF }); #endif @@ -694,67 +938,21 @@ void relaySetup() { _relayBackwards(); _relayConfigure(); _relayBoot(); - relayLoop(); + _relayLoop(); + + espurnaRegisterLoop(_relayLoop); #if WEB_SUPPORT relaySetupAPI(); relaySetupWS(); #endif - #if MQTT_SUPPORT relaySetupMQTT(); #endif + #if TERMINAL_SUPPORT + _relayInitCommands(); + #endif DEBUG_MSG_P(PSTR("[RELAY] Number of relays: %d\n"), _relays.size()); } - -void relayLoop(void) { - - unsigned char id; - - for (id = 0; id < _relays.size(); id++) { - - unsigned int current_time = millis(); - bool status = _relays[id].target_status; - - if ((_relays[id].current_status != status) - && (current_time >= _relays[id].change_time)) { - - DEBUG_MSG_P(PSTR("[RELAY] #%d set to %s\n"), id, status ? "ON" : "OFF"); - - // Call the provider to perform the action - _relayProviderStatus(id, status); - - // Send MQTT - #if MQTT_SUPPORT - relayMQTT(id); - #endif - - if (!_relayRecursive) { - relayPulse(id); - _relaySaveTicker.once_ms(RELAY_SAVE_DELAY, relaySave); - #if WEB_SUPPORT - wsSend(_relayWebSocketUpdate); - #endif - } - - #if DOMOTICZ_SUPPORT - domoticzSendRelay(id); - #endif - - #if INFLUXDB_SUPPORT - relayInfluxDB(id); - #endif - - // Flag relay-based LEDs to update status - ledUpdate(true); - - _relays[id].report = false; - _relays[id].group_report = false; - - } - - } - -} diff --git a/code/espurna/rf.ino b/code/espurna/rf.ino index 384fca8d..68756b6d 100644 --- a/code/espurna/rf.ino +++ b/code/espurna/rf.ino @@ -2,105 +2,191 @@ RF MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ #if RF_SUPPORT -#include +#include -unsigned long rfCode = 0; -unsigned long rfCodeON = 0; -unsigned long rfCodeOFF = 0; +RCSwitch * _rfModem; + +unsigned long _rf_learn_start = 0; +unsigned char _rf_learn_id = 0; +bool _rf_learn_status = true; +bool _rf_learn_active = false; // ----------------------------------------------------------------------------- // RF // ----------------------------------------------------------------------------- -void _rfWebSocketOnSend(JsonObject& root) { - root["rfVisible"] = 1; - root["rfChannel"] = getSetting("rfChannel", RF_CHANNEL); - root["rfDevice"] = getSetting("rfDevice", RF_DEVICE); +unsigned long _rfRetrieve(unsigned char id, bool status) { + String code = getSetting(status ? "rfbON" : "rfbOFF", id, "0"); + return strtoul(code.c_str(), 0, 16); } -void _rfBuildCodes() { +void _rfStore(unsigned char id, bool status, unsigned long code) { + DEBUG_MSG_P(PSTR("[RF] Storing %d-%s => %X\n"), id, status ? "ON" : "OFF", code); + char buffer[20]; + snprintf_P(buffer, sizeof(buffer), PSTR("%X"), code); + setSetting(status ? "rfbON" : "rfbOFF", id, buffer); +} - unsigned long code = 0; +void _rfLearn(unsigned char id, bool status) { + _rf_learn_start = millis(); + _rf_learn_id = id; + _rf_learn_status = status; + _rf_learn_active = true; +} - // channel - unsigned int channel = getSetting("rfChannel", RF_CHANNEL).toInt(); - for (byte i = 0; i < 5; i++) { - code *= 3; - if (channel & 1) code += 1; - channel >>= 1; - } +void _rfForget(unsigned char id, bool status) { + + delSetting(status ? "rfbON" : "rfbOFF", id); + + // Websocket update + #if WEB_SUPPORT + char wsb[100]; + snprintf_P(wsb, sizeof(wsb), PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"\"}]}"), id, status ? 1 : 0); + wsSend(wsb); + #endif + +} - // device - unsigned int device = getSetting("rfDevice", RF_DEVICE).toInt(); - for (byte i = 0; i < 5; i++) { - code *= 3; - if (device != i) code += 2; - } - // status - code *= 9; - rfCodeOFF = code + 2; - rfCodeON = code + 6; +bool _rfMatch(unsigned long code, unsigned char& relayID, unsigned char& value) { - DEBUG_MSG_P(PSTR("[RF] Code ON : %lu\n"), rfCodeON); - DEBUG_MSG_P(PSTR("[RF] Code OFF: %lu\n"), rfCodeOFF); + bool found = false; + DEBUG_MSG_P(PSTR("[RF] Trying to match code %X\n"), code); + + for (unsigned char i=0; i()); } -void rfSetup() { +// ----------------------------------------------------------------------------- + +void rfLoop() { + + if (_rfModem->available()) { + + static unsigned long last = 0; + if (millis() - last > RF_DEBOUNCE) { + last = millis(); + + if (_rfModem->getReceivedValue() > 0) { + + unsigned long rf_code = _rfModem->getReceivedValue(); + + DEBUG_MSG_P(PSTR("[RF] Received code: %X\n"), rf_code); + + if (_rf_learn_active) { + + _rf_learn_active = false; + + _rfStore(_rf_learn_id, _rf_learn_status, rf_code); - pinMode(RF_PIN, INPUT_PULLUP); - _rfBuildCodes(); - RemoteReceiver::init(RF_PIN, 3, rfCallback); - RemoteReceiver::disable(); - DEBUG_MSG_P(PSTR("[RF] Disabled\n")); + // Websocket update + #if WEB_SUPPORT + char wsb[100]; + snprintf_P( + wsb, sizeof(wsb), + PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"%X\"}]}"), + _rf_learn_id, _rf_learn_status ? 1 : 0, rf_code); + wsSend(wsb); + #endif - static WiFiEventHandler e1 = WiFi.onStationModeDisconnected([](const WiFiEventStationModeDisconnected& event) { - RemoteReceiver::disable(); - DEBUG_MSG_P(PSTR("[RF] Disabled\n")); - }); + } else { - static WiFiEventHandler e2 = WiFi.onSoftAPModeStationDisconnected([](const WiFiEventSoftAPModeStationDisconnected& event) { - RemoteReceiver::disable(); - DEBUG_MSG_P(PSTR("[RF] Disabled\n")); - }); + unsigned char id; + unsigned char value; + if (_rfMatch(rf_code, id, value)) { + if (2 == value) { + relayToggle(id); + } else { + relayStatus(id, 1 == value); + } + } - static WiFiEventHandler e3 = WiFi.onStationModeConnected([](const WiFiEventStationModeConnected& event) { - RemoteReceiver::enable(); - DEBUG_MSG_P(PSTR("[RF] Enabled\n")); - }); + } - static WiFiEventHandler e4 = WiFi.onSoftAPModeStationConnected([](const WiFiEventSoftAPModeStationConnected& event) { - RemoteReceiver::enable(); - DEBUG_MSG_P(PSTR("[RF] Enabled\n")); - }); + } + + } + + _rfModem->resetAvailable(); + + } + + if (_rf_learn_active && (millis() - _rf_learn_start > RF_LEARN_TIMEOUT)) { + _rf_learn_active = false; + } + +} + +void rfSetup() { + + _rfModem = new RCSwitch(); + _rfModem->enableReceive(RF_PIN); + DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), RF_PIN); #if WEB_SUPPORT wsOnSendRegister(_rfWebSocketOnSend); - wsOnAfterParseRegister(_rfBuildCodes); + wsOnActionRegister(_rfWebSocketOnAction); #endif + // Register loop + espurnaRegisterLoop(rfLoop); + } #endif diff --git a/code/espurna/rfbridge.ino b/code/espurna/rfbridge.ino index dbd60e8a..c19a7a74 100644 --- a/code/espurna/rfbridge.ino +++ b/code/espurna/rfbridge.ino @@ -2,28 +2,40 @@ ITEAD RF BRIDGE MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez */ #ifdef ITEAD_SONOFF_RFBRIDGE -#include +#include #include +#if RFB_DIRECT +#include +#endif + // ----------------------------------------------------------------------------- // DEFINITIONS // ----------------------------------------------------------------------------- -#define RF_MESSAGE_SIZE 9 -#define RF_CODE_START 0xAA -#define RF_CODE_ACK 0xA0 -#define RF_CODE_LEARN 0xA1 -#define RF_CODE_LEARN_KO 0xA2 -#define RF_CODE_LEARN_OK 0xA3 -#define RF_CODE_RFIN 0xA4 -#define RF_CODE_RFOUT 0xA5 -#define RF_CODE_STOP 0x55 +#define RF_MESSAGE_SIZE 9 +#define RF_MAX_MESSAGE_SIZE (112+4) +#define RF_CODE_START 0xAA +#define RF_CODE_ACK 0xA0 +#define RF_CODE_LEARN 0xA1 +#define RF_CODE_LEARN_KO 0xA2 +#define RF_CODE_LEARN_OK 0xA3 +#define RF_CODE_RFIN 0xA4 +#define RF_CODE_RFOUT 0xA5 +#define RF_CODE_SNIFFING_ON 0xA6 +#define RF_CODE_SNIFFING_OFF 0xA7 +#define RF_CODE_RFOUT_NEW 0xA8 +#define RF_CODE_LEARN_NEW 0xA9 +#define RF_CODE_LEARN_KO_NEW 0xAA +#define RF_CODE_LEARN_OK_NEW 0xAB +#define RF_CODE_RFOUT_BUCKET 0xB0 +#define RF_CODE_STOP 0x55 // ----------------------------------------------------------------------------- // GLOBALS TO THE MODULE @@ -39,16 +51,51 @@ typedef struct { byte code[RF_MESSAGE_SIZE]; byte times; } rfb_message_t; -std::vector _rfb_message_queue; -Ticker _rfbTicker; +static std::queue _rfb_message_queue; +Ticker _rfb_ticker; +bool _rfb_ticker_active = false; + +#if RFB_DIRECT + RCSwitch * _rfModem; + bool _learning = false; +#endif // ----------------------------------------------------------------------------- // PRIVATES // ----------------------------------------------------------------------------- +/* + From an hexa char array ("A220EE...") to a byte array (half the size) + */ +static int _rfbToArray(const char * in, byte * out, int length = RF_MESSAGE_SIZE * 2) { + int n = strlen(in); + if (n > RF_MAX_MESSAGE_SIZE*2 || (length > 0 && n != length)) return 0; + char tmp[3] = {0,0,0}; + n /= 2; + for (unsigned char p = 0; p()); } void _rfbAck() { - DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending ACK\n")); - Serial.println(); - Serial.write(RF_CODE_START); - Serial.write(RF_CODE_ACK); - Serial.write(RF_CODE_STOP); - Serial.flush(); - Serial.println(); + #if not RFB_DIRECT + DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending ACK\n")); + Serial.println(); + Serial.write(RF_CODE_START); + Serial.write(RF_CODE_ACK); + Serial.write(RF_CODE_STOP); + Serial.flush(); + Serial.println(); + #endif } void _rfbLearn() { - - DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending LEARN\n")); - Serial.println(); - Serial.write(RF_CODE_START); - Serial.write(RF_CODE_LEARN); - Serial.write(RF_CODE_STOP); - Serial.flush(); - Serial.println(); + #if RFB_DIRECT + DEBUG_MSG_P(PSTR("[RFBRIDGE] Entering LEARN mode\n")); + _learning = true; + #else + DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending LEARN\n")); + Serial.println(); + Serial.write(RF_CODE_START); + Serial.write(RF_CODE_LEARN); + Serial.write(RF_CODE_STOP); + Serial.flush(); + Serial.println(); + #endif #if WEB_SUPPORT char buffer[100]; @@ -94,26 +147,49 @@ void _rfbLearn() { } -void _rfbSend(byte * message) { - Serial.println(); - Serial.write(RF_CODE_START); - Serial.write(RF_CODE_RFOUT); - for (unsigned char j=0; jsetProtocol(protocol); + if (timing > 0) { + _rfModem->setPulseLength(timing); + } + _rfModem->send(rf_code, bitlength); + _rfModem->resetAvailable(); + #else + Serial.println(); + Serial.write(RF_CODE_START); + Serial.write(RF_CODE_RFOUT); + _rfbSendRaw(message); + Serial.write(RF_CODE_STOP); + Serial.flush(); + Serial.println(); + #endif } void _rfbSend() { // Check if there is something in the queue - if (_rfb_message_queue.size() == 0) return; + if (_rfb_message_queue.empty()) return; // Pop the first element rfb_message_t message = _rfb_message_queue.front(); - _rfb_message_queue.erase(_rfb_message_queue.begin()); + _rfb_message_queue.pop(); // Send the message _rfbSend(message.code); @@ -121,31 +197,51 @@ void _rfbSend() { // If it should be further sent, push it to the stack again if (message.times > 1) { message.times = message.times - 1; - _rfb_message_queue.push_back(message); + _rfb_message_queue.push(message); } // if there are still messages in the queue... - if (_rfb_message_queue.size() > 0) { - _rfbTicker.once_ms(RF_SEND_DELAY, _rfbSend); + if (_rfb_message_queue.empty()) { + _rfb_ticker.detach(); + _rfb_ticker_active = false; } } -void _rfbSend(byte * code, int times) { +void _rfbSend(byte * code, unsigned char times) { + #if RFB_DIRECT + times = 1; + #endif char buffer[RF_MESSAGE_SIZE]; _rfbToChar(code, buffer); - DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending MESSAGE '%s' %d time(s)\n"), buffer, times); + DEBUG_MSG_P(PSTR("[RFBRIDGE] Enqueuing MESSAGE '%s' %d time(s)\n"), buffer, times); rfb_message_t message; memcpy(message.code, code, RF_MESSAGE_SIZE); message.times = times; - _rfb_message_queue.push_back(message); - _rfbSend(); + _rfb_message_queue.push(message); + + // Enable the ticker if not running + if (!_rfb_ticker_active) { + _rfb_ticker_active = true; + _rfb_ticker.attach_ms(RF_SEND_DELAY, _rfbSend); + } } -bool _rfbMatch(char * code, unsigned char& relayID, unsigned char& value) { +#if RF_RAW_SUPPORT + +void _rfbSendRawOnce(byte *code, unsigned char length) { + char buffer[length*2]; + _rfbToChar(code, buffer, length); + DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending RAW MESSAGE '%s'\n"), buffer); + _rfbSendRaw(code, length); +} + +#endif // RF_RAW_SUPPORT + +bool _rfbMatch(char* code, unsigned char& relayID, unsigned char& value, char* buffer = NULL) { if (strlen(code) != 18) return false; @@ -161,6 +257,7 @@ bool _rfbMatch(char * code, unsigned char& relayID, unsigned char& value) { DEBUG_MSG_P(PSTR("[RFBRIDGE] Match ON code for relay %d\n"), i); value = 1; found = true; + if (buffer) strcpy(buffer, code_on.c_str()); } String code_off = rfbRetrieve(i, false); @@ -168,6 +265,7 @@ bool _rfbMatch(char * code, unsigned char& relayID, unsigned char& value) { DEBUG_MSG_P(PSTR("[RFBRIDGE] Match OFF code for relay %d\n"), i); if (found) value = 2; found = true; + if (buffer) strcpy(buffer, code_off.c_str()); } if (found) { @@ -199,12 +297,25 @@ void _rfbDecode() { #endif } + unsigned char id; + unsigned char status; + bool matched = false; + if (action == RF_CODE_LEARN_OK || action == RF_CODE_RFIN) { + _rfbAck(); + _rfbToChar(&_uartbuf[1], buffer); + + /* Look for the code, possibly replacing the code with the exact learned one on match + * we want to do this on learn too to be sure that the learned code is the same if it + * is equivalent + */ + DEBUG_MSG_P(PSTR("[RFBRIDGE] Received message '%s'\n"), buffer); + matched = _rfbMatch(buffer, id, status, buffer); + DEBUG_MSG_P(PSTR("[RFBRIDGE] Matched message '%s'\n"), buffer); + #if MQTT_SUPPORT - _rfbToChar(&_uartbuf[1], buffer); mqttSend(MQTT_TOPIC_RFIN, buffer); #endif - _rfbAck(); } if (action == RF_CODE_LEARN_OK) { @@ -222,13 +333,8 @@ void _rfbDecode() { } if (action == RF_CODE_RFIN) { - DEBUG_MSG_P(PSTR("[RFBRIDGE] Forward message '%s'\n"), buffer); - - // Look for the code - unsigned char id; - unsigned char status = 0; - if (_rfbMatch(buffer, id, status)) { + if (matched) { _rfbin = true; if (status == 2) { relayToggle(id); @@ -242,30 +348,77 @@ void _rfbDecode() { } void _rfbReceive() { - - static bool receiving = false; - - while (Serial.available()) { - - yield(); - byte c = Serial.read(); - //DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c); - - if (receiving) { - if (c == RF_CODE_STOP) { + #if RFB_DIRECT + static long learn_start = 0; + if (!_learning && learn_start) { + learn_start = 0; + } + if (_learning) { + if (!learn_start) { + DEBUG_MSG_P(PSTR("[RFBRIDGE] arming learn timeout\n")); + learn_start = millis(); + } + if (learn_start > 0 && millis() - learn_start > RF_LEARN_TIMEOUT) { + DEBUG_MSG_P(PSTR("[RFBRIDGE] learn timeout triggered\n")); + memset(_uartbuf, 0, sizeof(_uartbuf)); + _uartbuf[0] = RF_CODE_LEARN_KO; _rfbDecode(); - receiving = false; - } else { - _uartbuf[_uartpos++] = c; + _learning = false; } - } else if (c == RF_CODE_START) { - _uartpos = 0; - receiving = true; } - } + if (_rfModem->available()) { + static unsigned long last = 0; + if (millis() - last > RF_DEBOUNCE) { + last = millis(); + unsigned long rf_code = _rfModem->getReceivedValue(); + if ( rf_code > 0) { + DEBUG_MSG_P(PSTR("[RFBRIDGE] Received code: %08X\n"), rf_code); + unsigned int timing = _rfModem->getReceivedDelay(); + memset(_uartbuf, 0, sizeof(_uartbuf)); + unsigned char *msgbuf = _uartbuf + 1; + _uartbuf[0] = _learning ? RF_CODE_LEARN_OK: RF_CODE_RFIN; + msgbuf[0] = 0xC0; + msgbuf[1] = _rfModem->getReceivedProtocol(); + msgbuf[2] = timing >> 8; + msgbuf[3] = timing >> 0; + msgbuf[4] = _rfModem->getReceivedBitlength(); + msgbuf[5] = rf_code >> 24; + msgbuf[6] = rf_code >> 16; + msgbuf[7] = rf_code >> 8; + msgbuf[8] = rf_code >> 0; + _rfbDecode(); + _learning = false; + } + } + _rfModem->resetAvailable(); + } + #else + static bool receiving = false; + + while (Serial.available()) { + yield(); + byte c = Serial.read(); + //DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c); + if (receiving) { + if (c == RF_CODE_STOP && (_uartpos == 1 || _uartpos == RF_MESSAGE_SIZE + 1)) { + _rfbDecode(); + receiving = false; + } else if (_uartpos <= RF_MESSAGE_SIZE) { + _uartbuf[_uartpos++] = c; + } else { + // wrong message, should have received a RF_CODE_STOP + receiving = false; + } + } else if (c == RF_CODE_START) { + _uartpos = 0; + receiving = true; + } + + } + #endif } bool _rfbCompare(const char * code1, const char * code2) { @@ -276,29 +429,6 @@ bool _rfbSameOnOff(unsigned char id) { return _rfbCompare(rfbRetrieve(id, true).c_str(), rfbRetrieve(id, false).c_str()); } -/* -From an hexa char array ("A220EE...") to a byte array (half the size) - */ -bool _rfbToArray(const char * in, byte * out) { - if (strlen(in) != RF_MESSAGE_SIZE * 2) return false; - char tmp[3] = {0}; - for (unsigned char p = 0; p 0) && (isRFRaw || len != RF_MESSAGE_SIZE)) { + _rfbSendRawOnce(message, len); + } else { + tok = strtok(NULL, ","); + byte times = (tok != NULL) ? atoi(tok) : 1; + _rfbSend(message, times); + } + + #else // RF_RAW_SUPPORT + + byte message[RF_MESSAGE_SIZE]; + if (_rfbToArray(tok, message)) { + tok = strtok(NULL, ","); + byte times = (tok != NULL) ? atoi(tok) : 1; + _rfbSend(message, times); + } + + #endif // RF_RAW_SUPPORT } @@ -377,15 +534,47 @@ String rfbRetrieve(unsigned char id, bool status) { } void rfbStatus(unsigned char id, bool status) { + String value = rfbRetrieve(id, status); if (value.length() > 0) { + bool same = _rfbSameOnOff(id); - byte message[RF_MESSAGE_SIZE]; - _rfbToArray(value.c_str(), message); - unsigned char times = RF_SEND_TIMES; - if (same) times = _rfbin ? 0 : 1; - _rfbSend(message, times); + + #if RF_RAW_SUPPORT + + byte message[RF_MAX_MESSAGE_SIZE]; + int len = _rfbToArray(value.c_str(), message, 0); + + if (len == RF_MESSAGE_SIZE && // probably a standard msg + (message[0] != RF_CODE_START || // raw would start with 0xAA + message[1] != RF_CODE_RFOUT_BUCKET || // followed by 0xB0, + message[2] + 4 != len || // needs a valid length, + message[len-1] != RF_CODE_STOP)) { // and finish with 0x55 + + if (!_rfbin) { + unsigned char times = same ? 1 : RF_SEND_TIMES; + _rfbSend(message, times); + } + + } else { + _rfbSendRawOnce(message, len); // send a raw message + } + + #else // RF_RAW_SUPPORT + + if (!_rfbin) { + byte message[RF_MESSAGE_SIZE]; + _rfbToArray(value.c_str(), message); + unsigned char times = same ? 1 : RF_SEND_TIMES; + _rfbSend(message, times); + } + + #endif // RF_RAW_SUPPORT + } + + _rfbin = false; + } void rfbLearn(unsigned char id, bool status) { @@ -424,6 +613,18 @@ void rfbSetup() { wsOnActionRegister(_rfbWebSocketOnAction); #endif + #if RFB_DIRECT + _rfModem = new RCSwitch(); + _rfModem->enableReceive(RFB_RX_PIN); + _rfModem->enableTransmit(RFB_TX_PIN); + _rfModem->setRepeatTransmit(6); + DEBUG_MSG_P(PSTR("[RFBRIDGE] RF receiver on GPIO %u\n"), RFB_RX_PIN); + DEBUG_MSG_P(PSTR("[RFBRIDGE] RF transmitter on GPIO %u\n"), RFB_TX_PIN); + #endif + + // Register loop + espurnaRegisterLoop(rfbLoop); + } void rfbLoop() { diff --git a/code/espurna/scheduler.ino b/code/espurna/scheduler.ino new file mode 100644 index 00000000..003a6f69 --- /dev/null +++ b/code/espurna/scheduler.ino @@ -0,0 +1,227 @@ +/* + +SCHEDULER MODULE + +Copyright (C) 2017 by faina09 +Adapted by Xose Pérez + +*/ + +#if SCHEDULER_SUPPORT + +#include + +// ----------------------------------------------------------------------------- + +#if WEB_SUPPORT + +bool _schWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "sch", 3) == 0); +} + +void _schWebSocketOnSend(JsonObject &root){ + + if (relayCount() > 0) { + + root["schVisible"] = 1; + root["maxSchedules"] = SCHEDULER_MAX_SCHEDULES; + JsonArray &sch = root.createNestedArray("schedule"); + for (byte i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { + if (!hasSetting("schSwitch", i)) break; + JsonObject &scheduler = sch.createNestedObject(); + scheduler["schEnabled"] = getSetting("schEnabled", i, 1).toInt() == 1; + scheduler["schSwitch"] = getSetting("schSwitch", i, 0).toInt(); + scheduler["schAction"] = getSetting("schAction", i, 0).toInt(); + scheduler["schType"] = getSetting("schType", i, 0).toInt(); + scheduler["schHour"] = getSetting("schHour", i, 0).toInt(); + scheduler["schMinute"] = getSetting("schMinute", i, 0).toInt(); + scheduler["schUTC"] = getSetting("schUTC", i, 0).toInt() == 1; + scheduler["schWDs"] = getSetting("schWDs", i, ""); + } + + } + +} + +#endif // WEB_SUPPORT + +// ----------------------------------------------------------------------------- + +void _schConfigure() { + + bool delete_flag = false; + + for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { + + int sch_switch = getSetting("schSwitch", i, 0xFF).toInt(); + if (sch_switch == 0xFF) delete_flag = true; + + if (delete_flag) { + + delSetting("schEnabled", i); + delSetting("schSwitch", i); + delSetting("schAction", i); + delSetting("schHour", i); + delSetting("schMinute", i); + delSetting("schWDs", i); + delSetting("schType", i); + delSetting("schUTC", i); + + } else { + + #if DEBUG_SUPPORT + + bool sch_enabled = getSetting("schEnabled", i, 1).toInt() == 1; + int sch_action = getSetting("schAction", i, 0).toInt(); + int sch_hour = getSetting("schHour", i, 0).toInt(); + int sch_minute = getSetting("schMinute", i, 0).toInt(); + bool sch_utc = getSetting("schUTC", i, 0).toInt() == 1; + String sch_weekdays = getSetting("schWDs", i, ""); + unsigned char sch_type = getSetting("schType", i, SCHEDULER_TYPE_SWITCH).toInt(); + + DEBUG_MSG_P( + PSTR("[SCH] Schedule #%d: %s #%d to %d at %02d:%02d %s on %s%s\n"), + i, SCHEDULER_TYPE_SWITCH == sch_type ? "switch" : "channel", sch_switch, + sch_action, sch_hour, sch_minute, sch_utc ? "UTC" : "local time", + (char *) sch_weekdays.c_str(), + sch_enabled ? "" : " (disabled)" + ); + + #endif // DEBUG_SUPPORT + + } + + } + +} + +bool _schIsThisWeekday(time_t t, String weekdays){ + + // Convert from Sunday to Monday as day 1 + int w = weekday(t) - 1; + if (0 == w) w = 7; + + char pch; + char * p = (char *) weekdays.c_str(); + unsigned char position = 0; + while ((pch = p[position++])) { + if ((pch - '0') == w) return true; + } + return false; + +} + +int _schMinutesLeft(time_t t, unsigned char schedule_hour, unsigned char schedule_minute){ + unsigned char now_hour = hour(t); + unsigned char now_minute = minute(t); + return (schedule_hour - now_hour) * 60 + schedule_minute - now_minute; +} + +void _schCheck() { + + time_t local_time = now(); + time_t utc_time = ntpLocal2UTC(local_time); + + // Check schedules + for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { + + int sch_switch = getSetting("schSwitch", i, 0xFF).toInt(); + if (sch_switch == 0xFF) break; + + // Skip disabled schedules + if (getSetting("schEnabled", i, 1).toInt() == 0) continue; + + // Get the datetime used for the calculation + bool sch_utc = getSetting("schUTC", i, 0).toInt() == 1; + time_t t = sch_utc ? utc_time : local_time; + + String sch_weekdays = getSetting("schWDs", i, ""); + if (_schIsThisWeekday(t, sch_weekdays)) { + + int sch_hour = getSetting("schHour", i, 0).toInt(); + int sch_minute = getSetting("schMinute", i, 0).toInt(); + int minutes_to_trigger = _schMinutesLeft(t, sch_hour, sch_minute); + + if (minutes_to_trigger == 0) { + + unsigned char sch_type = getSetting("schType", i, SCHEDULER_TYPE_SWITCH).toInt(); + + if (SCHEDULER_TYPE_SWITCH == sch_type) { + int sch_action = getSetting("schAction", i, 0).toInt(); + DEBUG_MSG_P(PSTR("[SCH] Switching switch %d to %d\n"), sch_switch, sch_action); + if (sch_action == 2) { + relayToggle(sch_switch); + } else { + relayStatus(sch_switch, sch_action); + } + } + + #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + if (SCHEDULER_TYPE_DIM == sch_type) { + int sch_brightness = getSetting("schAction", i, -1).toInt(); + DEBUG_MSG_P(PSTR("[SCH] Set channel %d value to %d\n"), sch_switch, sch_brightness); + lightChannel(sch_switch, sch_brightness); + lightUpdate(true, true); + } + #endif + + DEBUG_MSG_P(PSTR("[SCH] Schedule #%d TRIGGERED!!\n"), i); + + // Show minutes to trigger every 15 minutes + // or every minute if less than 15 minutes to scheduled time. + // This only works for schedules on this same day. + // For instance, if your scheduler is set for 00:01 you will only + // get one notification before the trigger (at 00:00) + } else if (minutes_to_trigger > 0) { + + #if DEBUG_SUPPORT + if ((minutes_to_trigger % 15 == 0) || (minutes_to_trigger < 15)) { + DEBUG_MSG_P( + PSTR("[SCH] %d minutes to trigger schedule #%d\n"), + minutes_to_trigger, i + ); + } + #endif + + } + + } + + } + +} + +void _schLoop() { + + // Check time has been sync'ed + if (!ntpSynced()) return; + + // Check schedules every minute at hh:mm:00 + static unsigned long last_minute = 60; + unsigned char current_minute = minute(); + if (current_minute != last_minute) { + last_minute = current_minute; + _schCheck(); + } + +} + +// ----------------------------------------------------------------------------- + +void schSetup() { + + _schConfigure(); + + // Update websocket clients + #if WEB_SUPPORT + wsOnSendRegister(_schWebSocketOnSend); + wsOnReceiveRegister(_schWebSocketOnReceive); + wsOnAfterParseRegister(_schConfigure); + #endif + + // Register loop + espurnaRegisterLoop(_schLoop); + +} + +#endif // SCHEDULER_SUPPORT diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino index fefe633b..fd5309fa 100644 --- a/code/espurna/sensor.ino +++ b/code/espurna/sensor.ino @@ -2,7 +2,7 @@ SENSOR MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -28,57 +28,87 @@ typedef struct { std::vector _sensors; std::vector _magnitudes; +bool _sensors_ready = false; unsigned char _counts[MAGNITUDE_MAX]; bool _sensor_realtime = API_REAL_TIME_VALUES; unsigned long _sensor_read_interval = 1000 * SENSOR_READ_INTERVAL; unsigned char _sensor_report_every = SENSOR_REPORT_EVERY; +unsigned char _sensor_power_units = SENSOR_POWER_UNITS; +unsigned char _sensor_energy_units = SENSOR_ENERGY_UNITS; unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS; double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION; +double _sensor_humidity_correction = SENSOR_HUMIDITY_CORRECTION; + +String _sensor_energy_reset_ts = String(); // ----------------------------------------------------------------------------- // Private // ----------------------------------------------------------------------------- -String _magnitudeTopic(unsigned char type) { - char buffer[16] = {0}; - if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer)); - return String(buffer); -} - unsigned char _magnitudeDecimals(unsigned char type) { + + // Hardcoded decimals (these should be linked to the unit, instead of the magnitude) + + if (type == MAGNITUDE_ENERGY || + type == MAGNITUDE_ENERGY_DELTA) { + if (_sensor_energy_units == ENERGY_KWH) return 3; + } + if (type == MAGNITUDE_POWER_ACTIVE || + type == MAGNITUDE_POWER_APPARENT || + type == MAGNITUDE_POWER_REACTIVE) { + if (_sensor_power_units == POWER_KILOWATTS) return 3; + } if (type < MAGNITUDE_MAX) return pgm_read_byte(magnitude_decimals + type); return 0; -} -String _magnitudeUnits(unsigned char type) { - char buffer[8] = {0}; - if (type < MAGNITUDE_MAX) { - if ((type == MAGNITUDE_TEMPERATURE) && (_sensor_temperature_units == TMP_FAHRENHEIT)) { - strncpy_P(buffer, magnitude_fahrenheit, sizeof(buffer)); - } else { - strncpy_P(buffer, magnitude_units[type], sizeof(buffer)); - } - } - return String(buffer); } double _magnitudeProcess(unsigned char type, double value) { + + // Hardcoded conversions (these should be linked to the unit, instead of the magnitude) + if (type == MAGNITUDE_TEMPERATURE) { if (_sensor_temperature_units == TMP_FAHRENHEIT) value = value * 1.8 + 32; value = value + _sensor_temperature_correction; } + + if (type == MAGNITUDE_HUMIDITY) { + value = constrain(value + _sensor_humidity_correction, 0, 100); + } + + if (type == MAGNITUDE_ENERGY || + type == MAGNITUDE_ENERGY_DELTA) { + if (_sensor_energy_units == ENERGY_KWH) value = value / 3600000; + } + if (type == MAGNITUDE_POWER_ACTIVE || + type == MAGNITUDE_POWER_APPARENT || + type == MAGNITUDE_POWER_REACTIVE) { + if (_sensor_power_units == POWER_KILOWATTS) value = value / 1000; + } + return roundTo(value, _magnitudeDecimals(type)); + } // ----------------------------------------------------------------------------- #if WEB_SUPPORT +bool _sensorWebSocketOnReceive(const char * key, JsonVariant& value) { + if (strncmp(key, "pwr", 3) == 0) return true; + if (strncmp(key, "sns", 3) == 0) return true; + if (strncmp(key, "tmp", 3) == 0) return true; + if (strncmp(key, "hum", 3) == 0) return true; + if (strncmp(key, "energy", 6) == 0) return true; + return false; +} + void _sensorWebSocketSendData(JsonObject& root) { char buffer[10]; bool hasTemperature = false; + bool hasHumidity = false; JsonArray& list = root.createNestedArray("magnitudes"); for (unsigned char i=0; i<_magnitudes.size(); i++) { @@ -91,15 +121,23 @@ void _sensorWebSocketSendData(JsonObject& root) { element["index"] = int(magnitude.global); element["type"] = int(magnitude.type); element["value"] = String(buffer); - element["units"] = _magnitudeUnits(magnitude.type); - element["description"] = magnitude.sensor->slot(magnitude.local); + element["units"] = magnitudeUnits(magnitude.type); element["error"] = magnitude.sensor->error(); + if (magnitude.type == MAGNITUDE_ENERGY) { + if (_sensor_energy_reset_ts.length() == 0) _sensorReset(); + element["description"] = magnitude.sensor->slot(magnitude.local) + _sensor_energy_reset_ts; + } else { + element["description"] = magnitude.sensor->slot(magnitude.local); + } + if (magnitude.type == MAGNITUDE_TEMPERATURE) hasTemperature = true; + if (magnitude.type == MAGNITUDE_HUMIDITY) hasHumidity = true; } if (hasTemperature) root["temperatureVisible"] = 1; + if (hasHumidity) root["humidityVisible"] = 1; } @@ -112,6 +150,7 @@ void _sensorWebSocketStart(JsonObject& root) { #if EMON_ANALOG_SUPPORT if (sensor->getID() == SENSOR_EMON_ANALOG_ID) { root["emonVisible"] = 1; + root["pwrVisible"] = 1; root["pwrVoltage"] = ((EmonAnalogSensor *) sensor)->getVoltage(); } #endif @@ -119,6 +158,32 @@ void _sensorWebSocketStart(JsonObject& root) { #if HLW8012_SUPPORT if (sensor->getID() == SENSOR_HLW8012_ID) { root["hlwVisible"] = 1; + root["pwrVisible"] = 1; + } + #endif + + #if CSE7766_SUPPORT + if (sensor->getID() == SENSOR_CSE7766_ID) { + root["cseVisible"] = 1; + root["pwrVisible"] = 1; + } + #endif + + #if V9261F_SUPPORT + if (sensor->getID() == SENSOR_V9261F_ID) { + root["pwrVisible"] = 1; + } + #endif + + #if ECH1560_SUPPORT + if (sensor->getID() == SENSOR_ECH1560_ID) { + root["pwrVisible"] = 1; + } + #endif + + #if PZEM004T_SUPPORT + if (sensor->getID() == SENSOR_PZEM004T_ID) { + root["pwrVisible"] = 1; } #endif @@ -127,8 +192,11 @@ void _sensorWebSocketStart(JsonObject& root) { if (_magnitudes.size() > 0) { root["sensorsVisible"] = 1; //root["apiRealTime"] = _sensor_realtime; + root["pwrUnits"] = _sensor_power_units; + root["energyUnits"] = _sensor_energy_units; root["tmpUnits"] = _sensor_temperature_units; root["tmpCorrection"] = _sensor_temperature_correction; + root["humCorrection"] = _sensor_humidity_correction; root["snsRead"] = _sensor_read_interval / 1000; root["snsReport"] = _sensor_report_every; } @@ -158,7 +226,7 @@ void _sensorAPISetup() { sensor_magnitude_t magnitude = _magnitudes[magnitude_id]; - String topic = _magnitudeTopic(magnitude.type); + String topic = magnitudeTopic(magnitude.type); if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) topic = topic + "/" + String(magnitude.global); apiRegister(topic.c_str(), [magnitude_id](char * buffer, size_t len) { @@ -173,6 +241,26 @@ void _sensorAPISetup() { } #endif +#if TERMINAL_SUPPORT + +void _sensorInitCommands() { + settingsRegisterCommand(F("MAGNITUDES"), [](Embedis* e) { + for (unsigned char i=0; i<_magnitudes.size(); i++) { + sensor_magnitude_t magnitude = _magnitudes[i]; + DEBUG_MSG_P(PSTR("[SENSOR] * %2d: %s @ %s (%s/%d)\n"), + i, + magnitudeTopic(magnitude.type).c_str(), + magnitude.sensor->slot(magnitude.local).c_str(), + magnitudeTopic(magnitude.type).c_str(), + magnitude.global + ); + } + DEBUG_MSG_P(PSTR("+OK\n")); + }); +} + +#endif + void _sensorTick() { for (unsigned char i=0; i<_sensors.size(); i++) { _sensors[i]->tick(); @@ -197,11 +285,40 @@ void _sensorPost() { } } +void _sensorReset() { + #if NTP_SUPPORT + if (ntpSynced()) { + _sensor_energy_reset_ts = String(" (since ") + ntpDateTime() + String(")"); + } + #endif +} + // ----------------------------------------------------------------------------- // Sensor initialization // ----------------------------------------------------------------------------- -void _sensorInit() { +void _sensorLoad() { + + /* + + This is temporal, in the future sensors will be initialized based on + soft configuration (data stored in EEPROM config) so you will be able + to define and configure new sensors on the fly + + At the time being, only enabled sensors (those with *_SUPPORT to 1) are being + loaded and initialized here. If you want to add new sensors of the same type + just duplicate the block and change the arguments for the set* methods. + Check the DHT block below for an example + + */ + + #if AM2320_SUPPORT + { + AM2320Sensor * sensor = new AM2320Sensor(); + sensor->setAddress(AM2320_ADDRESS); + _sensors.push_back(sensor); + } + #endif #if ANALOG_SUPPORT { @@ -227,6 +344,14 @@ void _sensorInit() { } #endif + #if CSE7766_SUPPORT + { + CSE7766Sensor * sensor = new CSE7766Sensor(); + sensor->setRX(CSE7766_PIN); + _sensors.push_back(sensor); + } + #endif + #if DALLAS_SUPPORT { DallasSensor * sensor = new DallasSensor(); @@ -244,6 +369,19 @@ void _sensorInit() { } #endif + /* + // Example on how to add a second DHT sensor + // DHT2_PIN and DHT2_TYPE should be defined in sensors.h file + #if DHT_SUPPORT + { + DHTSensor * sensor = new DHTSensor(); + sensor->setGPIO(DHT2_PIN); + sensor->setType(DHT2_TYPE); + _sensors.push_back(sensor); + } + #endif + */ + #if DIGITAL_SUPPORT { DigitalSensor * sensor = new DigitalSensor(); @@ -312,6 +450,35 @@ void _sensorInit() { } #endif + #if GEIGER_SUPPORT + { + GeigerSensor * sensor = new GeigerSensor(); // Create instance of thr Geiger module. + sensor->setGPIO(GEIGER_PIN); // Interrupt pin of the attached geiger counter board. + sensor->setMode(GEIGER_PIN_MODE); // This pin is an input. + sensor->setDebounceTime(GEIGER_DEBOUNCE); // Debounce time 25ms, because https://github.com/Trickx/espurna/wiki/Geiger-counter + sensor->setInterruptMode(GEIGER_INTERRUPT_MODE); // Interrupt triggering: edge detection rising. + sensor->setCPM2SievertFactor(GEIGER_CPM2SIEVERT); // Conversion factor from counts per minute to µSv/h + _sensors.push_back(sensor); + } + #endif + + #if GUVAS12SD_SUPPORT + { + GUVAS12SDSensor * sensor = new GUVAS12SDSensor(); + sensor->setGPIO(GUVAS12SD_PIN); + _sensors.push_back(sensor); + } + #endif + + #if HCSR04_SUPPORT + { + HCSR04Sensor * sensor = new HCSR04Sensor(); + sensor->setTrigger(HCSR04_TRIGGER); + sensor->setEcho(HCSR04_ECHO); + _sensors.push_back(sensor); + } + #endif + #if HLW8012_SUPPORT { HLW8012Sensor * sensor = new HLW8012Sensor(); @@ -332,11 +499,34 @@ void _sensorInit() { } #endif + #if SENSEAIR_SUPPORT + { + SenseAirSensor * sensor = new SenseAirSensor(); + sensor->setRX(SENSEAIR_RX_PIN); + sensor->setTX(SENSEAIR_TX_PIN); + _sensors.push_back(sensor); + } + #endif + #if PMSX003_SUPPORT { PMSX003Sensor * sensor = new PMSX003Sensor(); sensor->setRX(PMS_RX_PIN); sensor->setTX(PMS_TX_PIN); + sensor->setType(PMS_TYPE); + _sensors.push_back(sensor); + } + #endif + + #if PZEM004T_SUPPORT + { + PZEM004TSensor * sensor = new PZEM004TSensor(); + #if PZEM004T_USE_SOFT + sensor->setRX(PZEM004T_RX_PIN); + sensor->setTX(PZEM004T_TX_PIN); + #else + sensor->setSerial(& PZEM004T_HW_PORT); + #endif _sensors.push_back(sensor); } #endif @@ -357,6 +547,14 @@ void _sensorInit() { } #endif + #if TMP3X_SUPPORT + { + TMP3XSensor * sensor = new TMP3XSensor(); + sensor->setType(TMP3X_TYPE); + _sensors.push_back(sensor); + } + #endif + #if V9261F_SUPPORT { V9261FSensor * sensor = new V9261FSensor(); @@ -368,21 +566,144 @@ void _sensorInit() { } +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 _sensorInit() { + + _sensors_ready = true; + + for (unsigned char i=0; i<_sensors.size(); i++) { + + // Do not process an already initialized sensor + if (_sensors[i]->ready()) continue; + DEBUG_MSG_P(PSTR("[SENSOR] Initializing %s\n"), _sensors[i]->description().c_str()); + + // Force sensor to reload config + _sensors[i]->begin(); + if (!_sensors[i]->ready()) { + if (_sensors[i]->error() != 0) DEBUG_MSG_P(PSTR("[SENSOR] -> ERROR %d\n"), _sensors[i]->error()); + _sensors_ready = false; + continue; + } + + // Initialize magnitudes + for (unsigned char k=0; k<_sensors[i]->count(); k++) { + + unsigned char type = _sensors[i]->type(k); + + sensor_magnitude_t new_magnitude; + new_magnitude.sensor = _sensors[i]; + new_magnitude.local = k; + new_magnitude.type = type; + new_magnitude.global = _counts[type]; + new_magnitude.current = 0; + new_magnitude.filtered = 0; + new_magnitude.reported = 0; + new_magnitude.min_change = 0; + if (type == MAGNITUDE_DIGITAL) { + 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. + new_magnitude.filter = new MovingAverageFilter(); + } else { + new_magnitude.filter = new MedianFilter(); + } + new_magnitude.filter->resize(_sensor_report_every); + _magnitudes.push_back(new_magnitude); + + DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), magnitudeTopic(type).c_str(), _counts[type]); + + _counts[type] = _counts[type] + 1; + + } + + // Hook callback + _sensors[i]->onEvent([i](unsigned char type, const char * payload) { + _sensorCallback(i, type, payload); + }); + + // Custom initializations + + #if EMON_ANALOG_SUPPORT + + if (_sensors[i]->getID() == SENSOR_EMON_ANALOG_ID) { + EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i]; + sensor->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat()); + sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt()); + } + + #endif // EMON_ANALOG_SUPPORT + + #if HLW8012_SUPPORT + + if (_sensors[i]->getID() == SENSOR_HLW8012_ID) { + + HLW8012Sensor * sensor = (HLW8012Sensor *) _sensors[i]; + + double value; + + value = getSetting("pwrRatioC", 0).toFloat(); + if (value > 0) sensor->setCurrentRatio(value); + + value = getSetting("pwrRatioV", 0).toFloat(); + if (value > 0) sensor->setVoltageRatio(value); + + value = getSetting("pwrRatioP", 0).toFloat(); + if (value > 0) sensor->setPowerRatio(value); + + } + + #endif // HLW8012_SUPPORT + + #if CSE7766_SUPPORT + + if (_sensors[i]->getID() == SENSOR_CSE7766_ID) { + + CSE7766Sensor * sensor = (CSE7766Sensor *) _sensors[i]; + + double value; + + value = getSetting("pwrRatioC", 0).toFloat(); + if (value > 0) sensor->setCurrentRatio(value); + + value = getSetting("pwrRatioV", 0).toFloat(); + if (value > 0) sensor->setVoltageRatio(value); + + value = getSetting("pwrRatioP", 0).toFloat(); + if (value > 0) sensor->setPowerRatio(value); + + } + + #endif // CSE7766_SUPPORT + + } + +} + void _sensorConfigure() { - double value; + // General sensor settings + _sensor_read_interval = 1000 * constrain(getSetting("snsRead", SENSOR_READ_INTERVAL).toInt(), SENSOR_READ_MIN_INTERVAL, SENSOR_READ_MAX_INTERVAL); + _sensor_report_every = constrain(getSetting("snsReport", SENSOR_REPORT_EVERY).toInt(), SENSOR_REPORT_MIN_EVERY, SENSOR_REPORT_MAX_EVERY); + _sensor_realtime = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1; + _sensor_power_units = getSetting("pwrUnits", SENSOR_POWER_UNITS).toInt(); + _sensor_energy_units = getSetting("energyUnits", SENSOR_ENERGY_UNITS).toInt(); + _sensor_temperature_units = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt(); + _sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat(); + _sensor_humidity_correction = getSetting("humCorrection", SENSOR_HUMIDITY_CORRECTION).toFloat(); + // Specific sensor settings for (unsigned char i=0; i<_sensors.size(); i++) { #if EMON_ANALOG_SUPPORT + if (_sensors[i]->getID() == SENSOR_EMON_ANALOG_ID) { + double value; EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i]; - if (value = getSetting("pwrExpectedP", 0).toInt() == 0) { - value = getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat(); - if (value > 0) sensor->setCurrentRatio(0, value); - } else { + if (value = getSetting("pwrExpectedP", 0).toInt()) { sensor->expectedPower(0, value); setSetting("pwrRatioC", sensor->getCurrentRatio(0)); } @@ -392,42 +713,63 @@ void _sensorConfigure() { delSetting("pwrRatioC"); } - sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt()); + if (getSetting("pwrResetE", 0).toInt() == 1) { + sensor->resetEnergy(); + _sensorReset(); + } + sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt()); } + #endif // EMON_ANALOG_SUPPORT - // Force sensor to reload config - _sensors[i]->begin(); + #if EMON_ADC121_SUPPORT + if (_sensors[i]->getID() == SENSOR_EMON_ADC121_ID) { + EmonADC121Sensor * sensor = (EmonADC121Sensor *) _sensors[i]; + if (getSetting("pwrResetE", 0).toInt() == 1) { + sensor->resetEnergy(); + _sensorReset(); + } + } + #endif + + #if EMON_ADS1X15_SUPPORT + if (_sensors[i]->getID() == SENSOR_EMON_ADS1X15_ID) { + EmonADS1X15Sensor * sensor = (EmonADS1X15Sensor *) _sensors[i]; + if (getSetting("pwrResetE", 0).toInt() == 1) { + sensor->resetEnergy(); + _sensorReset(); + } + } + #endif #if HLW8012_SUPPORT + + if (_sensors[i]->getID() == SENSOR_HLW8012_ID) { + double value; HLW8012Sensor * sensor = (HLW8012Sensor *) _sensors[i]; if (value = getSetting("pwrExpectedC", 0).toFloat()) { sensor->expectedCurrent(value); setSetting("pwrRatioC", sensor->getCurrentRatio()); - } else { - value = getSetting("pwrRatioC", 0).toFloat(); - if (value > 0) sensor->setCurrentRatio(value); } if (value = getSetting("pwrExpectedV", 0).toInt()) { sensor->expectedVoltage(value); setSetting("pwrRatioV", sensor->getVoltageRatio()); - } else { - value = getSetting("pwrRatioV", 0).toFloat(); - if (value > 0) sensor->setVoltageRatio(value); } if (value = getSetting("pwrExpectedP", 0).toInt()) { sensor->expectedPower(value); setSetting("pwrRatioP", sensor->getPowerRatio()); - } else { - value = getSetting("pwrRatioP", 0).toFloat(); - if (value > 0) sensor->setPowerRatio(value); + } + + if (getSetting("pwrResetE", 0).toInt() == 1) { + sensor->resetEnergy(); + _sensorReset(); } if (getSetting("pwrResetCalibration", 0).toInt() == 1) { @@ -438,70 +780,62 @@ void _sensorConfigure() { } } - #endif // HLW8012_SUPPORT - } - // General sensor settings - _sensor_read_interval = 1000 * constrain(getSetting("snsRead", SENSOR_READ_INTERVAL).toInt(), SENSOR_READ_MIN_INTERVAL, SENSOR_READ_MAX_INTERVAL); - _sensor_report_every = constrain(getSetting("snsReport", SENSOR_REPORT_EVERY).toInt(), SENSOR_REPORT_MIN_EVERY, SENSOR_REPORT_MAX_EVERY); - _sensor_realtime = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1; - _sensor_temperature_units = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt(); - _sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat(); - - // Update filter sizes - for (unsigned char i=0; i<_magnitudes.size(); i++) { - _magnitudes[i].filter->resize(_sensor_report_every); - } + #endif // HLW8012_SUPPORT - // Save settings - delSetting("pwrExpectedP"); - delSetting("pwrExpectedC"); - delSetting("pwrExpectedV"); - delSetting("pwrResetCalibration"); - //saveSettings(); + #if CSE7766_SUPPORT -} + if (_sensors[i]->getID() == SENSOR_CSE7766_ID) { -void _magnitudesInit() { + double value; + CSE7766Sensor * sensor = (CSE7766Sensor *) _sensors[i]; - for (unsigned char i=0; i<_sensors.size(); i++) { + if (value = getSetting("pwrExpectedC", 0).toFloat()) { + sensor->expectedCurrent(value); + setSetting("pwrRatioC", sensor->getCurrentRatio()); + } - BaseSensor * sensor = _sensors[i]; + if (value = getSetting("pwrExpectedV", 0).toInt()) { + sensor->expectedVoltage(value); + setSetting("pwrRatioV", sensor->getVoltageRatio()); + } - DEBUG_MSG_P(PSTR("[SENSOR] %s\n"), sensor->description().c_str()); - if (sensor->error() != 0) DEBUG_MSG_P(PSTR("[SENSOR] -> ERROR %d\n"), sensor->error()); + if (value = getSetting("pwrExpectedP", 0).toInt()) { + sensor->expectedPower(value); + setSetting("pwrRatioP", sensor->getPowerRatio()); + } - for (unsigned char k=0; kcount(); k++) { + if (getSetting("pwrResetE", 0).toInt() == 1) { + sensor->resetEnergy(); + _sensorReset(); + } - unsigned char type = sensor->type(k); + if (getSetting("pwrResetCalibration", 0).toInt() == 1) { + sensor->resetRatios(); + delSetting("pwrRatioC"); + delSetting("pwrRatioV"); + delSetting("pwrRatioP"); + } - sensor_magnitude_t new_magnitude; - new_magnitude.sensor = sensor; - new_magnitude.local = k; - new_magnitude.type = type; - new_magnitude.global = _counts[type]; - new_magnitude.current = 0; - new_magnitude.filtered = 0; - new_magnitude.reported = 0; - new_magnitude.min_change = 0; - if (type == MAGNITUDE_DIGITAL) { - new_magnitude.filter = new MaxFilter(); - } else if (type == MAGNITUDE_EVENTS) { - new_magnitude.filter = new MovingAverageFilter(); - } else { - new_magnitude.filter = new MedianFilter(); } - new_magnitude.filter->resize(_sensor_report_every); - _magnitudes.push_back(new_magnitude); - DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), _magnitudeTopic(type).c_str(), _counts[type]); - - _counts[type] = _counts[type] + 1; + #endif // CSE7766_SUPPORT - } + } + // Update filter sizes + for (unsigned char i=0; i<_magnitudes.size(); i++) { + _magnitudes[i].filter->resize(_sensor_report_every); } + // Save settings + delSetting("pwrExpectedP"); + delSetting("pwrExpectedC"); + delSetting("pwrExpectedV"); + delSetting("pwrResetCalibration"); + delSetting("pwrResetE"); + saveSettings(); + } // ----------------------------------------------------------------------------- @@ -538,23 +872,65 @@ unsigned char magnitudeIndex(unsigned char index) { return 0; } +String magnitudeTopic(unsigned char type) { + char buffer[16] = {0}; + if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer)); + return String(buffer); +} + +String magnitudeTopicIndex(unsigned char index) { + char topic[32] = {0}; + if (index < _magnitudes.size()) { + sensor_magnitude_t magnitude = _magnitudes[index]; + if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { + snprintf(topic, sizeof(topic), "%s/%u", magnitudeTopic(magnitude.type).c_str(), magnitude.global); + } else { + snprintf(topic, sizeof(topic), "%s", magnitudeTopic(magnitude.type).c_str()); + } + } + return String(topic); +} + + +String magnitudeUnits(unsigned char type) { + char buffer[8] = {0}; + if (type < MAGNITUDE_MAX) { + if ((type == MAGNITUDE_TEMPERATURE) && (_sensor_temperature_units == TMP_FAHRENHEIT)) { + strncpy_P(buffer, magnitude_fahrenheit, sizeof(buffer)); + } else if ( + (type == MAGNITUDE_ENERGY || type == MAGNITUDE_ENERGY_DELTA) && + (_sensor_energy_units == ENERGY_KWH)) { + strncpy_P(buffer, magnitude_kwh, sizeof(buffer)); + } else if ( + (type == MAGNITUDE_POWER_ACTIVE || type == MAGNITUDE_POWER_APPARENT || type == MAGNITUDE_POWER_REACTIVE) && + (_sensor_power_units == POWER_KILOWATTS)) { + strncpy_P(buffer, magnitude_kw, sizeof(buffer)); + } else { + strncpy_P(buffer, magnitude_units[type], sizeof(buffer)); + } + } + return String(buffer); +} + // ----------------------------------------------------------------------------- void sensorSetup() { + // Backwards compatibility + moveSetting("powerUnits", "pwrUnits"); + // Load sensors + _sensorLoad(); _sensorInit(); // Configure stored values _sensorConfigure(); - // Load magnitudes - _magnitudesInit(); - #if WEB_SUPPORT // Websockets wsOnSendRegister(_sensorWebSocketStart); + wsOnReceiveRegister(_sensorWebSocketOnReceive); wsOnSendRegister(_sensorWebSocketSendData); wsOnAfterParseRegister(_sensorConfigure); @@ -563,12 +939,25 @@ void sensorSetup() { #endif + #if TERMINAL_SUPPORT + _sensorInitCommands(); + #endif + + // Register loop + espurnaRegisterLoop(sensorLoop); + } void sensorLoop() { - static unsigned long last_update = 0; - static unsigned long report_count = 0; + // Check if we still have uninitialized sensors + static unsigned long last_init = 0; + if (!_sensors_ready) { + if (millis() - last_init > SENSOR_INIT_INTERVAL) { + last_init = millis(); + _sensorInit(); + } + } if (_magnitudes.size() == 0) return; @@ -576,6 +965,8 @@ void sensorLoop() { _sensorTick(); // Check if we should read new data + static unsigned long last_update = 0; + static unsigned long report_count = 0; if (millis() - last_update > _sensor_read_interval) { last_update = millis(); @@ -588,6 +979,11 @@ void sensorLoop() { // Pre-read hook _sensorPre(); + // Get the first relay state + #if SENSOR_POWER_CHECK_STATUS + bool relay_off = (relayCount() > 0) && (relayStatus(0) == 0); + #endif + // Get readings for (unsigned char i=0; i<_magnitudes.size(); i++) { @@ -595,26 +991,43 @@ void sensorLoop() { if (magnitude.sensor->status()) { - unsigned char decimals = _magnitudeDecimals(magnitude.type); - current = magnitude.sensor->value(magnitude.local); + + // Completely remove spurious values if relay is OFF + #if SENSOR_POWER_CHECK_STATUS + if (relay_off) { + if (magnitude.type == MAGNITUDE_POWER_ACTIVE || + magnitude.type == MAGNITUDE_POWER_REACTIVE || + magnitude.type == MAGNITUDE_POWER_APPARENT || + magnitude.type == MAGNITUDE_CURRENT || + magnitude.type == MAGNITUDE_ENERGY_DELTA + ) { + current = 0; + } + } + #endif + magnitude.filter->add(current); // Special case - if (magnitude.type == MAGNITUDE_EVENTS) current = magnitude.filter->result(); + if (magnitude.type == MAGNITUDE_EVENTS) { + current = magnitude.filter->result(); + } current = _magnitudeProcess(magnitude.type, current); _magnitudes[i].current = current; + unsigned char decimals = _magnitudeDecimals(magnitude.type); + // Debug #if SENSOR_DEBUG { dtostrf(current, 1-sizeof(buffer), decimals, buffer); DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"), magnitude.sensor->slot(magnitude.local).c_str(), - _magnitudeTopic(magnitude.type).c_str(), + magnitudeTopic(magnitude.type).c_str(), buffer, - _magnitudeUnits(magnitude.type).c_str() + magnitudeUnits(magnitude.type).c_str() ); } #endif // SENSOR_DEBUG @@ -633,22 +1046,38 @@ void sensorLoop() { _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 - if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { - mqttSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer); - } else { - mqttSend(_magnitudeTopic(magnitude.type).c_str(), buffer); - } + + 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); + idbSend(magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer); } else { - idbSend(_magnitudeTopic(magnitude.type).c_str(), buffer); + idbSend(magnitudeTopic(magnitude.type).c_str(), buffer); } #endif // INFLUXDB_SUPPORT + #if THINGSPEAK_SUPPORT + tspkEnqueueMeasurement(i, buffer); + #endif + #if DOMOTICZ_SUPPORT { char key[15]; @@ -685,6 +1114,10 @@ void sensorLoop() { wsSend(_sensorWebSocketSendData); #endif + #if THINGSPEAK_SUPPORT + if (report_count == 0) tspkFlush(); + #endif + } } diff --git a/code/espurna/sensors/AM2320Sensor.h b/code/espurna/sensors/AM2320Sensor.h new file mode 100644 index 00000000..80924bf3 --- /dev/null +++ b/code/espurna/sensors/AM2320Sensor.h @@ -0,0 +1,198 @@ +// ----------------------------------------------------------------------------- +// AM2320 Humidity & Temperature sensor over I2C +// Copyright (C) 2018 by Mustafa Tufan +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && AM2320_SUPPORT + +#pragma once + +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + +#include "Arduino.h" +#include "I2CSensor.h" + +// https://akizukidenshi.com/download/ds/aosong/AM2320.pdf +#define AM2320_I2C_READ_REGISTER_DATA 0x03 // Read one or more data registers +#define AM2320_I2C_WRITE_MULTIPLE_REGISTERS 0x10 // Multiple sets of binary data to write multiple registers +/* +Register | Address | Register | Address | Register | Address | Register | Address +-----------------+---------+--------------------+---------+-------------------------+---------+-----------+-------- +High humidity | 0x00 | Model High | 0x08 | Users register a high | 0x10 | Retention | 0x18 +Low humidity | 0x01 | Model Low | 0x09 | Users register a low | 0x11 | Retention | 0x19 +High temperature | 0x02 | The version number | 0x0A | Users register 2 high | 0x12 | Retention | 0x1A +Low temperature | 0x03 | Device ID(24-31)Bit| 0x0B | Users register 2 low | 0x13 | Retention | 0x1B +Retention | 0x04 | Device ID(24-31)Bit| 0x0C | Retention | 0x14 | Retention | 0x1C +Retention | 0x05 | Device ID(24-31)Bit| 0x0D | Retention | 0x15 | Retention | 0x1D +Retention | 0x06 | Device ID(24-31)Bit| 0x0E | Retention | 0x16 | Retention | 0x1E +Retention | 0x07 | Status Register | 0x0F | Retention | 0x17 | Retention | 0x1F +*/ + +class AM2320Sensor : public I2CSensor { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + AM2320Sensor(): I2CSensor() { + _count = 2; + _sensor_id = SENSOR_AM2320_ID; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + if (!_dirty) return; + + // I2C auto-discover + unsigned char addresses[] = {0x23, 0x5C, 0xB8}; + _address = _begin_i2c(_address, sizeof(addresses), addresses); + if (_address == 0) return; + + _ready = true; + _dirty = false; + } + + // Descriptive name of the sensor + String description() { + char buffer[25]; + snprintf(buffer, sizeof(buffer), "AM2320 @ I2C (0x%02X)", _address); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Type for slot # index + unsigned char type(unsigned char index) { + if (index == 0) return MAGNITUDE_TEMPERATURE; + if (index == 1) return MAGNITUDE_HUMIDITY; + return MAGNITUDE_NONE; + } + + // Pre-read hook (usually to populate registers with up-to-date data) + void pre() { + _error = SENSOR_ERROR_OK; + _read(); + } + + // Current value for slot # index + double value(unsigned char index) { + if (index == 0) return _temperature; + if (index == 1) return _humidity; + return 0; + } + + protected: + + // --------------------------------------------------------------------- + // Protected + // --------------------------------------------------------------------- + +/* + // Get device model, version, device_id + + void _init() { + i2c_wakeup(_address); + delayMicroseconds(800); + + unsigned char _buffer[11]; + + // 0x08 = read address + // 7 = number of bytes to read + if (i2c_write_uint8(_address, AM2320_I2C_READ_REGISTER_DATA, 0x08, 7) != I2C_TRANS_SUCCESS) { + _error = SENSOR_ERROR_TIMEOUT; + return false; + } + + uint16_t model = (_buffer[2] << 8) | _buffer[3]; + uint8_t version = _buffer[4]; + uint32_t device_id = _buffer[8] << 24 | _buffer[7] << 16 | _buffer[6] << 8 | _buffer[5]; + } +*/ + + void _read() { + + i2c_wakeup(_address); + + // waiting time of at least 800 μs, the maximum 3000 μs + delayMicroseconds(800); // just to be on safe side + + // 0x00 = read address + // 4 = number of bytes to read + if (i2c_write_uint8(_address, AM2320_I2C_READ_REGISTER_DATA, 0x00, 4) != I2C_TRANS_SUCCESS) { + _error = SENSOR_ERROR_TIMEOUT; + return; + } + + unsigned char _buffer[8]; + + // waiting time of at least 800 μs, the maximum 3000 μs + delayMicroseconds(800 + ((3000-800)/2) ); + i2c_read_buffer(_address, _buffer, 8); + + // Humidity : 01F4 = (1×256)+(F×16)+4 = 500 => humidity = 500÷10 = 50.0 % + // 0339 = (3×256)+(3×16)+9 = 825 => humidity = 825÷10 = 82.5 % + // Temperature: 00FA = (F×16)+A = 250 => temperature = 250÷10 = 25.0 C + // 0115 = (1×256)+(1×16)+5 = 277 => temperature = 277÷10 = 27.7 C + // Temperature resolution is 16Bit, temperature highest bit (Bit 15) is equal to 1 indicates a negative temperature + + // _buffer 0 = function code + // _buffer 1 = number of bytes + // _buffer 2-3 = high/low humidity + // _buffer 4-5 = high/low temperature + // _buffer 6-7 = CRC low/high + + unsigned int responseCRC = 0; + responseCRC = ((responseCRC | _buffer[7]) << 8 | _buffer[6]); + + if (responseCRC == _CRC16(_buffer)) { + int foo = (_buffer[2] << 8) | _buffer[3]; + _humidity = foo / 10.0; + + foo = ((_buffer[4] & 0x7F) << 8) | _buffer[5]; // clean bit 15 and merge + _temperature = foo / 10.0; + + if (_buffer[4] & 0x80) { // is bit 15 == 1 + _temperature = _temperature * -1; // negative temperature + } + + _error = SENSOR_ERROR_OK; + } else { + _error = SENSOR_ERROR_CRC; + return; + } + } + + unsigned int _CRC16(unsigned char buffer[]) { + unsigned int crc16 = 0xFFFF; + + for (unsigned int i = 0; i < 6; i++) { + crc16 ^= buffer[i]; + + for (unsigned int b = 8; b != 0; b--) { + if (crc16 & 0x01) { // is lsb set + crc16 >>= 1; + crc16 ^= 0xA001; + } else { + crc16 >>= 1; + } + } + } + + return crc16; + } + + double _temperature = 0; + double _humidity = 0; +}; + +#endif // SENSOR_SUPPORT && AM2320_SUPPORT diff --git a/code/espurna/sensors/AnalogSensor.h b/code/espurna/sensors/AnalogSensor.h index 12d76923..e988ab96 100644 --- a/code/espurna/sensors/AnalogSensor.h +++ b/code/espurna/sensors/AnalogSensor.h @@ -1,12 +1,16 @@ // ----------------------------------------------------------------------------- // Analog Sensor (maps to an analogRead) -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && ANALOG_SUPPORT #pragma once +// Set ADC to TOUT pin +#undef ADC_MODE_VALUE +#define ADC_MODE_VALUE ADC_TOUT + #include "Arduino.h" #include "BaseSensor.h" @@ -30,26 +34,33 @@ class AnalogSensor : public BaseSensor { // Initialization method, must be idempotent void begin() { pinMode(0, INPUT); + _ready = true; } // Descriptive name of the sensor String description() { - return String("ANALOG @ GPIO0"); + return String("ANALOG @ TOUT"); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String("0"); } // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_ANALOG; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return analogRead(0); - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } diff --git a/code/espurna/sensors/BH1750Sensor.h b/code/espurna/sensors/BH1750Sensor.h index 93b44448..20e56868 100644 --- a/code/espurna/sensors/BH1750Sensor.h +++ b/code/espurna/sensors/BH1750Sensor.h @@ -1,19 +1,17 @@ // ----------------------------------------------------------------------------- // BH1750 Liminosity sensor over I2C -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && BH1750_SUPPORT #pragma once +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + #include "Arduino.h" #include "I2CSensor.h" -#if I2C_USE_BRZO -#include -#else -#include -#endif #define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 // Start measurement at 1lx resolution. Measurement time is approx 120ms. #define BH1750_CONTINUOUS_HIGH_RES_MODE_2 0x11 // Start measurement at 0.5lx resolution. Measurement time is approx 120ms. @@ -60,16 +58,16 @@ class BH1750Sensor : public I2CSensor { void begin() { if (!_dirty) return; - _dirty = false; // I2C auto-discover unsigned char addresses[] = {0x23, 0x5C}; _address = _begin_i2c(_address, sizeof(addresses), addresses); if (_address == 0) return; - // Configure - _configure(); - delay(10); + // Run configuration on next update + _run_configure = true; + _ready = true; + _dirty = false; } @@ -82,44 +80,31 @@ class BH1750Sensor : public I2CSensor { // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_LUX; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } + // Pre-read hook (usually to populate registers with up-to-date data) + void pre() { + _error = SENSOR_ERROR_OK; + _lux = _read(); + } + // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; - if (index == 0) return _read(); - _error = SENSOR_ERROR_OUT_OF_RANGE; + if (index == 0) return _lux; return 0; } protected: - void _configure() { - #if I2C_USE_BRZO - uint8_t buffer[1] = {_mode}; - brzo_i2c_start_transaction(_address, I2C_SCL_FREQUENCY); - brzo_i2c_write(buffer, 1, false); - brzo_i2c_end_transaction(); - #else - Wire.beginTransmission(_address); - Wire.write(_mode); - Wire.endTransmission(); - #endif - } - double _read() { - double level; - uint8_t buffer[2]; - // For one-shot modes reconfigure sensor & wait for conversion - if (_mode & 0x20) { + if (_run_configure) { - _configure(); + // Configure mode + i2c_write_uint8(_address, _mode); // According to datasheet // conversion time is ~16ms for low resolution @@ -129,27 +114,25 @@ class BH1750Sensor : public I2CSensor { unsigned long start = millis(); while (millis() - start < wait) delay(1); + // Keep on running configure each time if one-shot mode + _run_configure = _mode & 0x20; + } - #if I2C_USE_BRZO - brzo_i2c_start_transaction(_address, I2C_SCL_FREQUENCY); - brzo_i2c_read(buffer, 2, false); - brzo_i2c_end_transaction(); - #else - Wire.beginTransmission(_address); - Wire.requestFrom(_address, (unsigned char) 2); - buffer[0] = Wire.read(); - buffer[1] = Wire.read(); - Wire.endTransmission(); - #endif - - level = buffer[0] * 256 + buffer[1]; + double level = (double) i2c_read_uint16(_address); + if (level == 0xFFFF) { + _error = SENSOR_ERROR_CRC; + _run_configure = true; + return 0; + } return level / 1.2; } unsigned char _mode; + bool _run_configure = false; + double _lux = 0; }; -#endif // SENSOR_SUPPORT && SI7021_SUPPORT +#endif // SENSOR_SUPPORT && BH1750_SUPPORT diff --git a/code/espurna/sensors/BMX280Sensor.h b/code/espurna/sensors/BMX280Sensor.h index 29d5aa2f..ad9a3ec2 100644 --- a/code/espurna/sensors/BMX280Sensor.h +++ b/code/espurna/sensors/BMX280Sensor.h @@ -1,19 +1,54 @@ // ----------------------------------------------------------------------------- // BME280/BMP280 Sensor over I2C -// Uses SparkFun BME280 library -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && BMX280_SUPPORT #pragma once +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + #include "Arduino.h" #include "I2CSensor.h" -#include -#define BMX280_CHIP_BMP280 0x58 -#define BMX280_CHIP_BME280 0x60 +#define BMX280_CHIP_BMP280 0x58 +#define BMX280_CHIP_BME280 0x60 + +#define BMX280_REGISTER_DIG_T1 0x88 +#define BMX280_REGISTER_DIG_T2 0x8A +#define BMX280_REGISTER_DIG_T3 0x8C + +#define BMX280_REGISTER_DIG_P1 0x8E +#define BMX280_REGISTER_DIG_P2 0x90 +#define BMX280_REGISTER_DIG_P3 0x92 +#define BMX280_REGISTER_DIG_P4 0x94 +#define BMX280_REGISTER_DIG_P5 0x96 +#define BMX280_REGISTER_DIG_P6 0x98 +#define BMX280_REGISTER_DIG_P7 0x9A +#define BMX280_REGISTER_DIG_P8 0x9C +#define BMX280_REGISTER_DIG_P9 0x9E + +#define BMX280_REGISTER_DIG_H1 0xA1 +#define BMX280_REGISTER_DIG_H2 0xE1 +#define BMX280_REGISTER_DIG_H3 0xE3 +#define BMX280_REGISTER_DIG_H4 0xE4 +#define BMX280_REGISTER_DIG_H5 0xE5 +#define BMX280_REGISTER_DIG_H6 0xE7 + +#define BMX280_REGISTER_CHIPID 0xD0 +#define BMX280_REGISTER_VERSION 0xD1 +#define BMX280_REGISTER_SOFTRESET 0xE0 + +#define BMX280_REGISTER_CAL26 0xE1 + +#define BMX280_REGISTER_CONTROLHUMID 0xF2 +#define BMX280_REGISTER_CONTROL 0xF4 +#define BMX280_REGISTER_CONFIG 0xF5 +#define BMX280_REGISTER_PRESSUREDATA 0xF7 +#define BMX280_REGISTER_TEMPDATA 0xFA +#define BMX280_REGISTER_HUMIDDATA 0xFD class BMX280Sensor : public I2CSensor { @@ -27,11 +62,6 @@ class BMX280Sensor : public I2CSensor { BMX280Sensor(): I2CSensor() { _sensor_id = SENSOR_BMX280_ID; - _bme = new BME280(); - } - - ~BMX280Sensor() { - delete _bme; } // --------------------------------------------------------------------- @@ -40,18 +70,9 @@ class BMX280Sensor : public I2CSensor { // Initialization method, must be idempotent void begin() { - if (!_dirty) return; - _dirty = false; - _chip = 0; - - // I2C auto-discover - _address = _begin_i2c(_address, sizeof(BMX280Sensor::addresses), BMX280Sensor::addresses); - if (_address == 0) return; - - // Init _init(); - + _dirty = !_ready; } // Descriptive name of the sensor @@ -63,58 +84,61 @@ class BMX280Sensor : public I2CSensor { // Type for slot # index unsigned char type(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - unsigned char i = 0; - #if BMX280_TEMPERATURE > 0 - if (index == i++) return MAGNITUDE_TEMPERATURE; - #endif - #if BMX280_PRESSURE > 0 - if (index == i++) return MAGNITUDE_PRESSURE; - #endif - #if BMX280_HUMIDITY > 0 - if (_chip == BMX280_CHIP_BME280) { - if (index == i) return MAGNITUDE_HUMIDITY; - } - #endif - } - _error = SENSOR_ERROR_OUT_OF_RANGE; + unsigned char i = 0; + #if BMX280_TEMPERATURE > 0 + if (index == i++) return MAGNITUDE_TEMPERATURE; + #endif + #if BMX280_PRESSURE > 0 + if (index == i++) return MAGNITUDE_PRESSURE; + #endif + #if BMX280_HUMIDITY > 0 + if (_chip == BMX280_CHIP_BME280) { + if (index == i) return MAGNITUDE_HUMIDITY; + } + #endif return MAGNITUDE_NONE; } // Pre-read hook (usually to populate registers with up-to-date data) virtual void pre() { + if (_run_init) { + i2cClearBus(); + _init(); + } + if (_chip == 0) { _error = SENSOR_ERROR_UNKNOWN_ID; return; } + _error = SENSOR_ERROR_OK; #if BMX280_MODE == 1 - forceRead(); + _forceRead(); #endif + _error = _read(); + + if (_error != SENSOR_ERROR_OK) { + _run_init = true; + } + } // Current value for slot # index double value(unsigned char index) { - - if (index < _count) { - _error = SENSOR_ERROR_OK; - unsigned char i = 0; - #if BMX280_TEMPERATURE > 0 - if (index == i++) return _bme->readTempC(); - #endif - #if BMX280_PRESSURE > 0 - if (index == i++) return _bme->readFloatPressure() / 100; - #endif - #if BMX280_HUMIDITY > 0 - if (_chip == BMX280_CHIP_BME280) { - if (index == i) return _bme->readFloatHumidity(); - } - #endif - } - _error = SENSOR_ERROR_OUT_OF_RANGE; + unsigned char i = 0; + #if BMX280_TEMPERATURE > 0 + if (index == i++) return _temperature; + #endif + #if BMX280_PRESSURE > 0 + if (index == i++) return _pressure / 100; + #endif + #if BMX280_HUMIDITY > 0 + if (_chip == BMX280_CHIP_BME280) { + if (index == i) return _humidity; + } + #endif return 0; } @@ -150,7 +174,7 @@ class BMX280Sensor : public I2CSensor { void getConfig(JsonObject& root) { root["sensor_id"] = _sensor_id; - root["address"] = getAddress(); + root["address"] = _address; }; void setConfig(JsonObject& root) { @@ -161,29 +185,35 @@ class BMX280Sensor : public I2CSensor { void _init() { - _bme->settings.commInterface = I2C_MODE; - _bme->settings.I2CAddress = _address; - _bme->settings.runMode = BMX280_MODE; - _bme->settings.tStandby = 0; - _bme->settings.filter = 0; - _bme->settings.tempOverSample = BMX280_TEMPERATURE; - _bme->settings.pressOverSample = BMX280_PRESSURE; - _bme->settings.humidOverSample = BMX280_HUMIDITY; + // Make sure sensor had enough time to turn on. BMX280 requires 2ms to start up + nice_delay(10); - // Fix when not measuring temperature, t_fine should have a sensible value - if (BMX280_TEMPERATURE == 0) _bme->t_fine = 100000; // aprox 20ºC + // No chip ID by default + _chip = 0; - // Make sure sensor had enough time to turn on. BMX280 requires 2ms to start up - delay(10); + // I2C auto-discover + _address = _begin_i2c(_address, sizeof(BMX280Sensor::addresses), BMX280Sensor::addresses); + if (_address == 0) return; // Check sensor correctly initialized - _chip = _bme->begin(); + _chip = i2c_read_uint8(_address, BMX280_REGISTER_CHIPID); if ((_chip != BMX280_CHIP_BME280) && (_chip != BMX280_CHIP_BMP280)) { + _chip = 0; i2cReleaseLock(_address); + _previous_address = 0; _error = SENSOR_ERROR_UNKNOWN_ID; + + // Setting _address to 0 forces auto-discover + // This might be necessary at this stage if there is a + // different sensor in the hardcoded address + _address = 0; + + return; + } + _count = 0; #if BMX280_TEMPERATURE > 0 ++_count; #endif @@ -194,11 +224,53 @@ class BMX280Sensor : public I2CSensor { if (_chip == BMX280_CHIP_BME280) ++_count; #endif - _measurement_delay = measurementTime(); + _readCoefficients(); + + unsigned char data = 0; + i2c_write_uint8(_address, BMX280_REGISTER_CONTROL, data); + + data = (BMX280_STANDBY << 0x5) & 0xE0; + data |= (BMX280_FILTER << 0x02) & 0x1C; + i2c_write_uint8(_address, BMX280_REGISTER_CONFIG, data); + data = (BMX280_HUMIDITY) & 0x07; + i2c_write_uint8(_address, BMX280_REGISTER_CONTROLHUMID, data); + + data = (BMX280_TEMPERATURE << 5) & 0xE0; + data |= (BMX280_PRESSURE << 2) & 0x1C; + data |= (BMX280_MODE) & 0x03; + i2c_write_uint8(_address, BMX280_REGISTER_CONTROL, data); + + _measurement_delay = _measurementTime(); + _run_init = false; + _ready = true; + + } + + void _readCoefficients() { + _bmx280_calib.dig_T1 = i2c_read_uint16_le(_address, BMX280_REGISTER_DIG_T1); + _bmx280_calib.dig_T2 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_T2); + _bmx280_calib.dig_T3 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_T3); + + _bmx280_calib.dig_P1 = i2c_read_uint16_le(_address, BMX280_REGISTER_DIG_P1); + _bmx280_calib.dig_P2 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P2); + _bmx280_calib.dig_P3 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P3); + _bmx280_calib.dig_P4 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P4); + _bmx280_calib.dig_P5 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P5); + _bmx280_calib.dig_P6 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P6); + _bmx280_calib.dig_P7 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P7); + _bmx280_calib.dig_P8 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P8); + _bmx280_calib.dig_P9 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_P9); + + _bmx280_calib.dig_H1 = i2c_read_uint8(_address, BMX280_REGISTER_DIG_H1); + _bmx280_calib.dig_H2 = i2c_read_int16_le(_address, BMX280_REGISTER_DIG_H2); + _bmx280_calib.dig_H3 = i2c_read_uint8(_address, BMX280_REGISTER_DIG_H3); + _bmx280_calib.dig_H4 = (i2c_read_uint8(_address, BMX280_REGISTER_DIG_H4) << 4) | (i2c_read_uint8(_address, BMX280_REGISTER_DIG_H4+1) & 0xF); + _bmx280_calib.dig_H5 = (i2c_read_uint8(_address, BMX280_REGISTER_DIG_H5+1) << 4) | (i2c_read_uint8(_address, BMX280_REGISTER_DIG_H5) >> 4); + _bmx280_calib.dig_H6 = (int8_t) i2c_read_uint8(_address, BMX280_REGISTER_DIG_H6); } - unsigned long measurementTime() { + unsigned long _measurementTime() { // Measurement Time (as per BMX280 datasheet section 9.1) // T_max(ms) = 1.25 @@ -224,23 +296,141 @@ class BMX280Sensor : public I2CSensor { } - void forceRead() { + void _forceRead() { // We set the sensor in "forced mode" to force a reading. // After the reading the sensor will go back to sleep mode. - uint8_t value = _bme->readRegister(BME280_CTRL_MEAS_REG); + uint8_t value = i2c_read_uint8(_address, BMX280_REGISTER_CONTROL); value = (value & 0xFC) + 0x01; - _bme->writeRegister(BME280_CTRL_MEAS_REG, value); + i2c_write_uint8(_address, BMX280_REGISTER_CONTROL, value); + + nice_delay(_measurement_delay); + + } + + unsigned char _read() { + + #if BMX280_TEMPERATURE > 0 + int32_t adc_T = i2c_read_uint16(_address, BMX280_REGISTER_TEMPDATA); + if (0xFFFF == adc_T) return SENSOR_ERROR_I2C; + adc_T <<= 8; + adc_T |= i2c_read_uint8(_address, BMX280_REGISTER_TEMPDATA+2); + adc_T >>= 4; + + int32_t var1t = ((((adc_T>>3) - + ((int32_t)_bmx280_calib.dig_T1 <<1))) * + ((int32_t)_bmx280_calib.dig_T2)) >> 11; + + int32_t var2t = (((((adc_T>>4) - + ((int32_t)_bmx280_calib.dig_T1)) * + ((adc_T>>4) - ((int32_t)_bmx280_calib.dig_T1))) >> 12) * + ((int32_t)_bmx280_calib.dig_T3)) >> 14; + + int32_t t_fine = var1t + var2t; + + double T = (t_fine * 5 + 128) >> 8; + _temperature = T / 100; + #else + int32_t t_fine = 102374; // ~20ºC + #endif + + // ----------------------------------------------------------------- + + #if BMX280_PRESSURE > 0 + int64_t var1, var2, p; + + int32_t adc_P = i2c_read_uint16(_address, BMX280_REGISTER_PRESSUREDATA); + if (0xFFFF == adc_P) return SENSOR_ERROR_I2C; + adc_P <<= 8; + adc_P |= i2c_read_uint8(_address, BMX280_REGISTER_PRESSUREDATA+2); + adc_P >>= 4; + + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)_bmx280_calib.dig_P6; + var2 = var2 + ((var1*(int64_t)_bmx280_calib.dig_P5)<<17); + var2 = var2 + (((int64_t)_bmx280_calib.dig_P4)<<35); + var1 = ((var1 * var1 * (int64_t)_bmx280_calib.dig_P3)>>8) + + ((var1 * (int64_t)_bmx280_calib.dig_P2)<<12); + var1 = (((((int64_t)1)<<47)+var1))*((int64_t)_bmx280_calib.dig_P1)>>33; + if (var1 == 0) return SENSOR_ERROR_I2C; // avoid exception caused by division by zero + + p = 1048576 - adc_P; + p = (((p<<31) - var2)*3125) / var1; + var1 = (((int64_t)_bmx280_calib.dig_P9) * (p>>13) * (p>>13)) >> 25; + var2 = (((int64_t)_bmx280_calib.dig_P8) * p) >> 19; + + p = ((p + var1 + var2) >> 8) + (((int64_t)_bmx280_calib.dig_P7)<<4); + _pressure = (double) p / 256; + #endif + + // ----------------------------------------------------------------- + + #if BMX280_HUMIDITY > 0 + if (_chip == BMX280_CHIP_BME280) { + + int32_t adc_H = i2c_read_uint16(_address, BMX280_REGISTER_HUMIDDATA); + if (0xFFFF == adc_H) return SENSOR_ERROR_I2C; + + int32_t v_x1_u32r; + + v_x1_u32r = (t_fine - ((int32_t)76800)); + + v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bmx280_calib.dig_H4) << 20) - + (((int32_t)_bmx280_calib.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * + (((((((v_x1_u32r * ((int32_t)_bmx280_calib.dig_H6)) >> 10) * + (((v_x1_u32r * ((int32_t)_bmx280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + + ((int32_t)2097152)) * ((int32_t)_bmx280_calib.dig_H2) + 8192) >> 14)); + + v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((int32_t)_bmx280_calib.dig_H1)) >> 4)); + + v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; + v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; + double h = (v_x1_u32r >> 12); + _humidity = h / 1024.0; + + } + #endif - delay(_measurement_delay); + return SENSOR_ERROR_OK; } // --------------------------------------------------------------------- - BME280 * _bme = NULL; unsigned char _chip; unsigned long _measurement_delay; + bool _run_init = false; + double _temperature = 0; + double _pressure = 0; + double _humidity = 0; + + typedef struct { + + uint16_t dig_T1; + int16_t dig_T2; + int16_t dig_T3; + + uint16_t dig_P1; + int16_t dig_P2; + int16_t dig_P3; + int16_t dig_P4; + int16_t dig_P5; + int16_t dig_P6; + int16_t dig_P7; + int16_t dig_P8; + int16_t dig_P9; + + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; + + } bmx280_calib_t; + + bmx280_calib_t _bmx280_calib; }; diff --git a/code/espurna/sensors/BaseSensor.h b/code/espurna/sensors/BaseSensor.h index 394e2418..9f3854f6 100644 --- a/code/espurna/sensors/BaseSensor.h +++ b/code/espurna/sensors/BaseSensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Abstract sensor class (other sensor classes extend this class) -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT @@ -10,8 +10,6 @@ #include #include -#define GPIO_NONE 0x99 - #define SENSOR_ERROR_OK 0 // No error #define SENSOR_ERROR_OUT_OF_RANGE 1 // Result out of sensor range #define SENSOR_ERROR_WARM_UP 2 // Sensor is warming-up @@ -20,6 +18,10 @@ #define SENSOR_ERROR_CRC 5 // Sensor data corrupted #define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address #define SENSOR_ERROR_GPIO_USED 7 // The GPIO is already in use +#define SENSOR_ERROR_CALIBRATION 8 // Calibration error or Not calibrated +#define SENSOR_ERROR_OTHER 99 // Any other error + +typedef std::function TSensorCallback; class BaseSensor { @@ -46,6 +48,12 @@ class BaseSensor { // Descriptive name of the sensor virtual String description() {} + // Address of the sensor (it could be the GPIO or I2C address) + virtual String address(unsigned char index) {} + + // Descriptive name of the slot # index + virtual String slot(unsigned char index) {}; + // Type for slot # index virtual unsigned char type(unsigned char index) {} @@ -61,14 +69,14 @@ class BaseSensor { // Load the configuration manifest static void manifest(JsonArray& root) {}; - // Descriptive name of the slot # index - String slot(unsigned char index) { return description(); } - // Sensor ID unsigned char getID() { return _sensor_id; }; - // Return sensor status (true for ready) - bool status() { return _error == 0; } + // Return status (true if no errors) + bool status() { return 0 == _error; } + + // Return ready status (true for ready) + bool ready() { return _ready; } // Return sensor last internal error int error() { return _error; } @@ -76,12 +84,17 @@ class BaseSensor { // Number of available slots unsigned char count() { return _count; } + // Hook for event callback + void onEvent(TSensorCallback fn) { _callback = fn; }; + protected: + TSensorCallback _callback = NULL; unsigned char _sensor_id = 0x00; int _error = 0; bool _dirty = true; unsigned char _count = 0; + bool _ready = false; }; diff --git a/code/espurna/sensors/CSE7766Sensor.h b/code/espurna/sensors/CSE7766Sensor.h new file mode 100644 index 00000000..7aa58364 --- /dev/null +++ b/code/espurna/sensors/CSE7766Sensor.h @@ -0,0 +1,378 @@ +// ----------------------------------------------------------------------------- +// CSE7766 based power monitor +// Copyright (C) 2018 by Xose Pérez +// http://www.chipsea.com/UploadFiles/2017/08/11144342F01B5662.pdf +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && CSE7766_SUPPORT + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" + +#include + +class CSE7766Sensor : public BaseSensor { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + CSE7766Sensor(): BaseSensor(), _data() { + _count = 4; + _sensor_id = SENSOR_CSE7766_ID; + } + + ~CSE7766Sensor() { + if (_serial) delete _serial; + } + + // --------------------------------------------------------------------- + + void setRX(unsigned char pin_rx) { + if (_pin_rx == pin_rx) return; + _pin_rx = pin_rx; + _dirty = true; + } + + void setInverted(bool inverted) { + if (_inverted == inverted) return; + _inverted = inverted; + _dirty = true; + } + + // --------------------------------------------------------------------- + + unsigned char getRX() { + return _pin_rx; + } + + bool getInverted() { + return _inverted; + } + + // --------------------------------------------------------------------- + + void expectedCurrent(double expected) { + if ((expected > 0) && (_current > 0)) { + _ratioC = _ratioC * (expected / _current); + } + } + + void expectedVoltage(unsigned int expected) { + if ((expected > 0) && (_voltage > 0)) { + _ratioV = _ratioV * (expected / _voltage); + } + } + + void expectedPower(unsigned int expected) { + if ((expected > 0) && (_active > 0)) { + _ratioP = _ratioP * (expected / _active); + } + } + + void setCurrentRatio(double value) { + _ratioC = value; + }; + + void setVoltageRatio(double value) { + _ratioV = value; + }; + + void setPowerRatio(double value) { + _ratioP = value; + }; + + double getCurrentRatio() { + return _ratioC; + }; + + double getVoltageRatio() { + return _ratioV; + }; + + double getPowerRatio() { + return _ratioP; + }; + + void resetRatios() { + _ratioC = _ratioV = _ratioP = 1.0; + } + + void resetEnergy() { + _energy = 0; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + + if (!_dirty) return; + + if (_serial) delete _serial; + + if (1 == _pin_rx) { + Serial.begin(CSE7766_BAUDRATE); + } else { + _serial = new SoftwareSerial(_pin_rx, SW_SERIAL_UNUSED_PIN, _inverted, 32); + _serial->enableIntTx(false); + _serial->begin(CSE7766_BAUDRATE); + } + + _ready = true; + _dirty = false; + + } + + // Descriptive name of the sensor + String description() { + char buffer[28]; + if (1 == _pin_rx) { + snprintf(buffer, sizeof(buffer), "CSE7766 @ HwSerial"); + } else { + snprintf(buffer, sizeof(buffer), "CSE7766 @ SwSerial(%u,NULL)", _pin_rx); + } + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String(_pin_rx); + } + + // Loop-like method, call it in your main loop + void tick() { + _read(); + } + + // Type for slot # index + unsigned char type(unsigned char index) { + if (index == 0) return MAGNITUDE_CURRENT; + if (index == 1) return MAGNITUDE_VOLTAGE; + if (index == 2) return MAGNITUDE_POWER_ACTIVE; + if (index == 3) return MAGNITUDE_ENERGY; + return MAGNITUDE_NONE; + } + + // Current value for slot # index + double value(unsigned char index) { + if (index == 0) return _current; + if (index == 1) return _voltage; + if (index == 2) return _active; + if (index == 3) return _energy; + return 0; + } + + protected: + + // --------------------------------------------------------------------- + // Protected + // --------------------------------------------------------------------- + + /** + * " + * Checksum is the sum of all data + * except for packet header and packet tail lowering by 8bit (...) + * " + * @return bool + */ + bool _checksum() { + unsigned char checksum = 0; + for (unsigned char i = 2; i < 23; i++) { + checksum += _data[i]; + } + return checksum == _data[23]; + } + + void _process() { + + // Sample data: + // 55 5A 02 E9 50 00 03 31 00 3E 9E 00 0D 30 4F 44 F8 00 12 65 F1 81 76 72 (w/ load) + // F2 5A 02 E9 50 00 03 2B 00 3E 9E 02 D7 7C 4F 44 F8 CF A5 5D E1 B3 2A B4 (w/o load) + + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] CSE7766: _process: "); + for (byte i=0; i<24; i++) DEBUG_MSG("%02X ", _data[i]); + DEBUG_MSG("\n"); + #endif + + // Checksum + if (!_checksum()) { + _error = SENSOR_ERROR_CRC; + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] CSE7766: Checksum error\n"); + #endif + return; + } + + // Calibration + if (0xAA == _data[0]) { + _error = SENSOR_ERROR_CALIBRATION; + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] CSE7766: Chip not calibrated\n"); + #endif + return; + } + + if ((_data[0] & 0xFC) > 0xF0) { + _error = SENSOR_ERROR_OTHER; + #if SENSOR_DEBUG + if (0xF1 == _data[0] & 0xF1) DEBUG_MSG("[SENSOR] CSE7766: Abnormal coefficient storage area\n"); + if (0xF2 == _data[0] & 0xF2) DEBUG_MSG("[SENSOR] CSE7766: Power cycle exceeded range\n"); + if (0xF4 == _data[0] & 0xF4) DEBUG_MSG("[SENSOR] CSE7766: Current cycle exceeded range\n"); + if (0xF8 == _data[0] & 0xF8) DEBUG_MSG("[SENSOR] CSE7766: Voltage cycle exceeded range\n"); + #endif + return; + } + + // Calibration coefficients + unsigned long _coefV = (_data[2] << 16 | _data[3] << 8 | _data[4] ); // 190770 + unsigned long _coefC = (_data[8] << 16 | _data[9] << 8 | _data[10]); // 16030 + unsigned long _coefP = (_data[14] << 16 | _data[15] << 8 | _data[16]); // 5195000 + + // Adj: this looks like a sampling report + uint8_t adj = _data[20]; // F1 11110001 + + // Calculate voltage + _voltage = 0; + if ((adj & 0x40) == 0x40) { + unsigned long voltage_cycle = _data[5] << 16 | _data[6] << 8 | _data[7]; // 817 + _voltage = _ratioV * _coefV / voltage_cycle / CSE7766_V2R; // 190700 / 817 = 233.41 + } + + // Calculate power + _active = 0; + if ((adj & 0x10) == 0x10) { + if ((_data[0] & 0xF2) != 0xF2) { + unsigned long power_cycle = _data[17] << 16 | _data[18] << 8 | _data[19]; // 4709 + _active = _ratioP * _coefP / power_cycle / CSE7766_V1R / CSE7766_V2R; // 5195000 / 4709 = 1103.20 + } + } + + // Calculate current + _current = 0; + if ((adj & 0x20) == 0x20) { + if (_active > 0) { + unsigned long current_cycle = _data[11] << 16 | _data[12] << 8 | _data[13]; // 3376 + _current = _ratioC * _coefC / current_cycle / CSE7766_V1R; // 16030 / 3376 = 4.75 + } + } + + // Calculate energy + unsigned int difference; + static unsigned int cf_pulses_last = 0; + unsigned int cf_pulses = _data[21] << 8 | _data[22]; + if (0 == cf_pulses_last) cf_pulses_last = cf_pulses; + if (cf_pulses < cf_pulses_last) { + difference = cf_pulses + (0xFFFF - cf_pulses_last) + 1; + } else { + difference = cf_pulses - cf_pulses_last; + } + _energy += difference * (float) _coefP / 1000000.0; + cf_pulses_last = cf_pulses; + + } + + void _read() { + + _error = SENSOR_ERROR_OK; + + static unsigned char index = 0; + static unsigned long last = millis(); + + while (_serial_available()) { + + // A 24 bytes message takes ~55ms to go through at 4800 bps + // Reset counter if more than 1000ms have passed since last byte. + if (millis() - last > CSE7766_SYNC_INTERVAL) index = 0; + last = millis(); + + uint8_t byte = _serial_read(); + + // first byte must be 0x55 or 0xF? + if (0 == index) { + if ((0x55 != byte) && (byte < 0xF0)) { + continue; + } + + // second byte must be 0x5A + } else if (1 == index) { + if (0x5A != byte) { + index = 0; + continue; + } + } + + _data[index++] = byte; + if (index > 23) { + _serial_flush(); + break; + } + + } + + // Process packet + if (24 == index) { + _process(); + index = 0; + } + + } + + // --------------------------------------------------------------------- + + bool _serial_available() { + if (1 == _pin_rx) { + return Serial.available(); + } else { + return _serial->available(); + } + } + + void _serial_flush() { + if (1 == _pin_rx) { + return Serial.flush(); + } else { + return _serial->flush(); + } + } + + uint8_t _serial_read() { + if (1 == _pin_rx) { + return Serial.read(); + } else { + return _serial->read(); + } + } + + // --------------------------------------------------------------------- + + unsigned int _pin_rx = CSE7766_PIN; + bool _inverted = CSE7766_PIN_INVERSE; + SoftwareSerial * _serial = NULL; + + double _active = 0; + double _voltage = 0; + double _current = 0; + double _energy = 0; + + double _ratioV = 1.0; + double _ratioC = 1.0; + double _ratioP = 1.0; + + unsigned char _data[24]; + +}; + +#endif // SENSOR_SUPPORT && CSE7766_SUPPORT diff --git a/code/espurna/sensors/DHTSensor.h b/code/espurna/sensors/DHTSensor.h index ba4e48b0..2651eadb 100644 --- a/code/espurna/sensors/DHTSensor.h +++ b/code/espurna/sensors/DHTSensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // DHTXX Sensor -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && DHT_SUPPORT @@ -33,7 +33,7 @@ class DHTSensor : public BaseSensor { } ~DHTSensor() { - if (_previous != 0xFF) gpioReleaseLock(_previous); + if (_previous != GPIO_NONE) gpioReleaseLock(_previous); } // --------------------------------------------------------------------- @@ -66,8 +66,8 @@ class DHTSensor : public BaseSensor { _count = 0; // Manage GPIO lock - if (_previous != 0xFF) gpioReleaseLock(_previous); - _previous = 0xFF; + if (_previous != GPIO_NONE) gpioReleaseLock(_previous); + _previous = GPIO_NONE; if (!gpioGetLock(_gpio)) { _error = SENSOR_ERROR_GPIO_USED; return; @@ -75,11 +75,13 @@ class DHTSensor : public BaseSensor { _previous = _gpio; _count = 2; + _ready = true; } // Pre-read hook (usually to populate registers with up-to-date data) void pre() { + _error = SENSOR_ERROR_OK; _read(); } @@ -90,21 +92,27 @@ class DHTSensor : public BaseSensor { return String(buffer); } + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String(_gpio); + } + // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_TEMPERATURE; if (index == 1) return MAGNITUDE_HUMIDITY; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return _temperature; if (index == 1) return _humidity; - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } @@ -132,12 +140,16 @@ class DHTSensor : public BaseSensor { if (++_errors > DHT_MAX_ERRORS) { _errors = 0; digitalWrite(_gpio, HIGH); - delay(250); + nice_delay(250); } pinMode(_gpio, OUTPUT); noInterrupts(); digitalWrite(_gpio, LOW); - delayMicroseconds(_type == DHT_CHIP_DHT11 ? 20000 : 500); + if (_type == DHT_CHIP_DHT11) { + nice_delay(20); + } else { + delayMicroseconds(500); + } digitalWrite(_gpio, HIGH); delayMicroseconds(40); pinMode(_gpio, INPUT_PULLUP); @@ -218,15 +230,15 @@ class DHTSensor : public BaseSensor { return uSec; } - unsigned char _gpio; - unsigned char _previous = 0xFF; + unsigned char _gpio = GPIO_NONE; + unsigned char _previous = GPIO_NONE; unsigned char _type = DHT_CHIP_DHT22; unsigned long _last_ok = 0; unsigned char _errors = 0; - double _temperature; - unsigned int _humidity; + double _temperature = 0; + unsigned int _humidity = 0; }; diff --git a/code/espurna/sensors/DallasSensor.h b/code/espurna/sensors/DallasSensor.h index dadd0f1e..16f70e37 100644 --- a/code/espurna/sensors/DallasSensor.h +++ b/code/espurna/sensors/DallasSensor.h @@ -1,7 +1,7 @@ // ----------------------------------------------------------------------------- // Dallas OneWire Sensor // Uses OneWire library -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && DALLAS_SUPPORT @@ -18,15 +18,13 @@ #define DS_CHIP_DS18B20 0x28 #define DS_CHIP_DS1825 0x3B +#define DS_DATA_SIZE 9 #define DS_PARASITE 1 #define DS_DISCONNECTED -127 #define DS_CMD_START_CONVERSION 0x44 #define DS_CMD_READ_SCRATCHPAD 0xBE -#define DS_ERROR_FAILED_RESET -2 -#define DS_ERROR_FAILED_READ -3 - class DallasSensor : public BaseSensor { public: @@ -41,7 +39,7 @@ class DallasSensor : public BaseSensor { ~DallasSensor() { if (_wire) delete _wire; - if (_previous != 0xFF) gpioReleaseLock(_previous); + if (_previous != GPIO_NONE) gpioReleaseLock(_previous); } // --------------------------------------------------------------------- @@ -66,11 +64,10 @@ class DallasSensor : public BaseSensor { void begin() { if (!_dirty) return; - _dirty = false; // Manage GPIO lock - if (_previous != 0xFF) gpioReleaseLock(_previous); - _previous = 0xFF; + if (_previous != GPIO_NONE) gpioReleaseLock(_previous); + _previous = GPIO_NONE; if (!gpioGetLock(_gpio)) { _error = SENSOR_ERROR_GPIO_USED; return; @@ -95,6 +92,8 @@ class DallasSensor : public BaseSensor { } else { _previous = _gpio; } + _ready = true; + _dirty = false; } @@ -121,38 +120,26 @@ class DallasSensor : public BaseSensor { // Read scratchpad if (_wire->reset() == 0) { - _error = DS_ERROR_FAILED_RESET; + // Force a CRC check error + _devices[index].data[0] = _devices[index].data[0] + 1; return; } _wire->select(_devices[index].address); _wire->write(DS_CMD_READ_SCRATCHPAD); - uint8_t data[9]; - for (unsigned char i = 0; i < 9; i++) { + uint8_t data[DS_DATA_SIZE]; + for (unsigned char i = 0; i < DS_DATA_SIZE; i++) { data[i] = _wire->read(); } - #if false - Serial.printf("[DS18B20] Data = "); - for (unsigned char i = 0; i < 9; i++) { - Serial.printf("%02X ", data[i]); - } - Serial.printf(" CRC = %02X\n", OneWire::crc8(data, 8)); - #endif - - if (_wire->reset() != 1) { - _error = DS_ERROR_FAILED_READ; - return; - } - - if (OneWire::crc8(data, 8) != data[8]) { - _error = SENSOR_ERROR_CRC; + // Force a CRC check error + _devices[index].data[0] = _devices[index].data[0] + 1; return; } - memcpy(_devices[index].data, data, 9); + memcpy(_devices[index].data, data, DS_DATA_SIZE); } @@ -170,9 +157,21 @@ class DallasSensor : public BaseSensor { return String(buffer); } + // Address of the device + String address(unsigned char index) { + char buffer[20] = {0}; + if (index < _count) { + uint8_t * address = _devices[index].address; + snprintf(buffer, sizeof(buffer), "%02X%02X%02X%02X%02X%02X%02X%02X", + address[0], address[1], address[2], address[3], + address[4], address[5], address[6], address[7] + ); + } + return String(buffer); + } + // Descriptive name of the slot # index String slot(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index < _count) { char buffer[40]; uint8_t * address = _devices[index].address; @@ -184,28 +183,32 @@ class DallasSensor : public BaseSensor { ); return String(buffer); } - _error = SENSOR_ERROR_OUT_OF_RANGE; return String(); } // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index < _count) return MAGNITUDE_TEMPERATURE; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } + // Pre-read hook (usually to populate registers with up-to-date data) + void pre() { + _error = SENSOR_ERROR_OK; + } + // Current value for slot # index double value(unsigned char index) { - if (index >= _count) { - _error = SENSOR_ERROR_OUT_OF_RANGE; - return 0; - } + if (index >= _count) return 0; uint8_t * data = _devices[index].data; + if (OneWire::crc8(data, DS_DATA_SIZE-1) != data[DS_DATA_SIZE-1]) { + _error = SENSOR_ERROR_CRC; + return 0; + } + // Registers // byte 0: temperature LSB // byte 1: temperature MSB @@ -239,7 +242,7 @@ class DallasSensor : public BaseSensor { _error = SENSOR_ERROR_CRC; return 0; } - _error = SENSOR_ERROR_OK; + return value; } @@ -294,12 +297,12 @@ class DallasSensor : public BaseSensor { typedef struct { uint8_t address[8]; - uint8_t data[9]; + uint8_t data[DS_DATA_SIZE]; } ds_device_t; std::vector _devices; - unsigned char _gpio; - unsigned char _previous = 0xFF; + unsigned char _gpio = GPIO_NONE; + unsigned char _previous = GPIO_NONE; OneWire * _wire = NULL; }; diff --git a/code/espurna/sensors/DigitalSensor.h b/code/espurna/sensors/DigitalSensor.h index e72607da..fc1ca796 100644 --- a/code/espurna/sensors/DigitalSensor.h +++ b/code/espurna/sensors/DigitalSensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Digital Sensor (maps to a digitalRead) -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && DIGITAL_SUPPORT @@ -58,6 +58,7 @@ class DigitalSensor : public BaseSensor { // Initialization method, must be idempotent void begin() { pinMode(_gpio, _mode); + _ready = true; } // Descriptive name of the sensor @@ -67,19 +68,25 @@ class DigitalSensor : public BaseSensor { return String(buffer); } + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String(_gpio); + } + // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_DIGITAL; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return (digitalRead(_gpio) == _default) ? 0 : 1; - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } diff --git a/code/espurna/sensors/ECH1560Sensor.h b/code/espurna/sensors/ECH1560Sensor.h index c4b87cbc..894ec72b 100644 --- a/code/espurna/sensors/ECH1560Sensor.h +++ b/code/espurna/sensors/ECH1560Sensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // ECH1560 based power monitor -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && ECH1560_SUPPORT @@ -18,7 +18,7 @@ class ECH1560Sensor : public BaseSensor { // Public // --------------------------------------------------------------------- - ECH1560Sensor(): BaseSensor() { + ECH1560Sensor(): BaseSensor(), _data() { _count = 3; _sensor_id = SENSOR_ECH1560_ID; } @@ -67,38 +67,53 @@ class ECH1560Sensor : public BaseSensor { void begin() { if (!_dirty) return; - _dirty = false; pinMode(_clk, INPUT); pinMode(_miso, INPUT); _enableInterrupts(true); + _dirty = false; + _ready = true; + + } + + // Loop-like method, call it in your main loop + void tick() { + if (_dosync) _sync(); } // Descriptive name of the sensor String description() { - char buffer[25]; - snprintf(buffer, sizeof(buffer), "ECH1560 @ GPIO(%i,%i)", _clk, _miso); + char buffer[35]; + snprintf(buffer, sizeof(buffer), "ECH1560 (CLK,SDO) @ GPIO(%u,%u)", _clk, _miso); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[6]; + snprintf(buffer, sizeof(buffer), "%u:%u", _clk, _miso); return String(buffer); } // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_CURRENT; if (index == 1) return MAGNITUDE_VOLTAGE; if (index == 2) return MAGNITUDE_POWER_APPARENT; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return _current; if (index == 1) return _voltage; if (index == 2) return _apparent; - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } @@ -111,7 +126,7 @@ class ECH1560Sensor : public BaseSensor { _clk_count = 0; - // register how long the ClkHigh is high to evaluate if we are at the part wher clk goes high for 1-2 ms + // register how long the ClkHigh is high to evaluate if we are at the part where clk goes high for 1-2 ms while (digitalRead(_clk) == HIGH) { _clk_count += 1; delayMicroseconds(30); //can only use delayMicroseconds in an interrupt. @@ -173,17 +188,17 @@ class ECH1560Sensor : public BaseSensor { while (_bits_count < 40); // skip the uninteresting 5 first bytes _bits_count = 0; - while (_bits_count < 24) { // loop through the next 3 Bytes (6-8) and save byte 6 and 7 in Ba and Bb + while (_bits_count < 24) { // loop through the next 3 Bytes (6-8) and save byte 6 and 7 in byte1 and byte2 if (_nextbit) { - if (_bits_count < 9) { // first Byte/8 bits in Ba + if (_bits_count < 9) { // first Byte/8 bits in byte1 byte1 = byte1 << 1; if (digitalRead(_miso) == HIGH) byte1 |= 1; _nextbit = false; - } else if (_bits_count < 17) { // bit 9-16 is byte 7, stor in Bb + } else if (_bits_count < 17) { // bit 9-16 is byte 7, store in byte2 byte2 = byte2 << 1; if (digitalRead(_miso) == HIGH) byte2 |= 1; @@ -195,9 +210,9 @@ class ECH1560Sensor : public BaseSensor { } - if (byte2 != 3) { // if bit Bb is not 3, we have reached the important part, U is allready in Ba and Bb and next 8 Bytes will give us the Power. + if (byte2 != 3) { // if bit byte2 is not 3, we have reached the important part, U is allready in byte1 and byte2 and next 8 Bytes will give us the Power. - // voltage = 2 * (Ba + Bb / 255) + // voltage = 2 * (byte1 + byte2 / 255) _voltage = 2.0 * ((float) byte1 + (float) byte2 / 255.0); // power: @@ -209,7 +224,7 @@ class ECH1560Sensor : public BaseSensor { byte2 = 0; byte3 = 0; - while (_bits_count < 24) { //store byte 6, 7 and 8 in Ba and Bb & Bc. + while (_bits_count < 24) { //store byte 6, 7 and 8 in byte1 and byte2 & byte3. if (_nextbit) { @@ -241,7 +256,7 @@ class ECH1560Sensor : public BaseSensor { byte3 = 255 - byte3; } - // power = (Ba*255+Bb+Bc/255)/2 + // power = (byte1*255+byte2+byte3/255)/2 _apparent = ( (float) byte1 * 255 + (float) byte2 + (float) byte3 / 255.0) / 2; _current = _apparent / _voltage; @@ -249,9 +264,13 @@ class ECH1560Sensor : public BaseSensor { } - // If Bb is not 3 or something else than 0, something is wrong! - if (byte2 == 0) _dosync = false; - + // If byte2 is not 3 or something else than 0, something is wrong! + if (byte2 == 0) { + _dosync = false; + #if SENSOR_DEBUG + DEBUG_MSG_P(PSTR("Nothing connected, or out of sync!\n")); + #endif + } } // --------------------------------------------------------------------- diff --git a/code/espurna/sensors/EmonADC121Sensor.h b/code/espurna/sensors/EmonADC121Sensor.h index 4bf9deaf..293b5c95 100644 --- a/code/espurna/sensors/EmonADC121Sensor.h +++ b/code/espurna/sensors/EmonADC121Sensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // ADS121-based Energy Monitor Sensor over I2C -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && EMON_ADC121_SUPPORT @@ -8,13 +8,7 @@ #pragma once #include "Arduino.h" -#include "EmonAnalogSensor.h" - -#if I2C_USE_BRZO -#include -#else -#include -#endif +#include "EmonSensor.h" // ADC121 Registers #define ADC121_REG_RESULT 0x00 @@ -29,7 +23,7 @@ #define ADC121_RESOLUTION 12 #define ADC121_CHANNELS 1 -class EmonADC121Sensor : public EmonAnalogSensor { +class EmonADC121Sensor : public EmonSensor { public: @@ -37,7 +31,7 @@ class EmonADC121Sensor : public EmonAnalogSensor { // Public // --------------------------------------------------------------------- - EmonADC121Sensor(): EmonAnalogSensor() { + EmonADC121Sensor(): EmonSensor() { _channels = ADC121_CHANNELS; _sensor_id = SENSOR_EMON_ADC121_ID; init(); @@ -59,19 +53,7 @@ class EmonADC121Sensor : public EmonAnalogSensor { if (_address == 0) return; // Init sensor - #if I2C_USE_BRZO - uint8_t buffer[2]; - buffer[0] = ADC121_REG_CONFIG; - buffer[1] = 0x00; - brzo_i2c_start_transaction(_address, I2C_SCL_FREQUENCY); - brzo_i2c_write(buffer, 2, false); - brzo_i2c_end_transaction(); - #else - Wire.beginTransmission(_address); - Wire.write(ADC121_REG_CONFIG); - Wire.write(0x00); - Wire.endTransmission(); - #endif + _init(); // Just one channel _count = _magnitudes; @@ -102,8 +84,49 @@ class EmonADC121Sensor : public EmonAnalogSensor { return; } - EmonAnalogSensor:pre(); + _current[0] = read(0); + + #if EMON_REPORT_ENERGY + static unsigned long last = 0; + if (last > 0) { + _energy[0] += (_current[0] * _voltage * (millis() - last) / 1000); + } + last = millis(); + #endif + + _error = SENSOR_ERROR_OK; + + } + + // Type for slot # index + unsigned char type(unsigned char index) { + unsigned char i=0; + #if EMON_REPORT_CURRENT + if (index == i++) return MAGNITUDE_CURRENT; + #endif + #if EMON_REPORT_POWER + if (index == i++) return MAGNITUDE_POWER_APPARENT; + #endif + #if EMON_REPORT_ENERGY + if (index == i) return MAGNITUDE_ENERGY; + #endif + return MAGNITUDE_NONE; + } + // Current value for slot # index + double value(unsigned char index) { + unsigned char channel = index / _magnitudes; + unsigned char i=0; + #if EMON_REPORT_CURRENT + if (index == i++) return _current[channel]; + #endif + #if EMON_REPORT_POWER + if (index == i++) return _current[channel] * _voltage; + #endif + #if EMON_REPORT_ENERGY + if (index == i) return _energy[channel]; + #endif + return 0; } protected: @@ -112,32 +135,14 @@ class EmonADC121Sensor : public EmonAnalogSensor { // Protected // --------------------------------------------------------------------- - unsigned int readADC(unsigned char channel) { + void _init() { + i2c_write_uint8(_address, ADC121_REG_CONFIG, 0); + } + unsigned int readADC(unsigned char channel) { (void) channel; - - unsigned int value; - - #if I2C_USE_BRZO - uint8_t buffer[2]; - buffer[0] = ADC121_REG_RESULT; - brzo_i2c_start_transaction(_address, I2C_SCL_FREQUENCY); - brzo_i2c_write(buffer, 1, false); - brzo_i2c_read(buffer, 2, false); - brzo_i2c_end_transaction(); - value = (buffer[0] & 0x0F) << 8; - value |= buffer[1]; - #else - Wire.beginTransmission(_address); - Wire.write(ADC121_REG_RESULT); - Wire.endTransmission(); - Wire.requestFrom(_address, (unsigned char) 2); - value = (Wire.read() & 0x0F) << 8; - value = value + Wire.read(); - #endif - + unsigned int value = i2c_read_uint16(_address, ADC121_REG_RESULT) & 0x0FFF; return value; - } }; diff --git a/code/espurna/sensors/EmonADS1X15Sensor.h b/code/espurna/sensors/EmonADS1X15Sensor.h index 2691da9e..d24472d1 100644 --- a/code/espurna/sensors/EmonADS1X15Sensor.h +++ b/code/espurna/sensors/EmonADS1X15Sensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // ADS1X15-based Energy Monitor Sensor over I2C -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && EMON_ADS1X15_SUPPORT @@ -10,12 +10,6 @@ #include "Arduino.h" #include "EmonSensor.h" -#if I2C_USE_BRZO - #include -#else - #include -#endif - #define ADS1X15_CHANNELS (4) #define ADS1X15_CHIP_ADS1015 (0) @@ -153,7 +147,6 @@ class EmonADS1X15Sensor : public EmonSensor { void begin() { if (!_dirty) return; - _dirty = false; // Discover unsigned char addresses[] = {0x48, 0x49, 0x4A, 0x4B}; @@ -203,23 +196,27 @@ class EmonADS1X15Sensor : public EmonSensor { return String(buffer); } + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[10]; + unsigned char channel = getChannel(index % _ports); + snprintf(buffer, sizeof(buffer), "0x%02X:%u", _address, channel); + return String(buffer); + } + // Type for slot # index unsigned char type(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - unsigned char magnitude = index / _ports; - unsigned char i=0; - #if EMON_REPORT_CURRENT - if (magnitude == i++) return MAGNITUDE_CURRENT; - #endif - #if EMON_REPORT_POWER - if (magnitude == i++) return MAGNITUDE_POWER_APPARENT; - #endif - #if EMON_REPORT_ENERGY - if (magnitude == i) return MAGNITUDE_ENERGY; - #endif - } - _error = SENSOR_ERROR_OUT_OF_RANGE; + unsigned char magnitude = index / _ports; + unsigned char i=0; + #if EMON_REPORT_CURRENT + if (magnitude == i++) return MAGNITUDE_CURRENT; + #endif + #if EMON_REPORT_POWER + if (magnitude == i++) return MAGNITUDE_POWER_APPARENT; + #endif + #if EMON_REPORT_ENERGY + if (magnitude == i) return MAGNITUDE_ENERGY; + #endif return MAGNITUDE_NONE; } @@ -233,33 +230,24 @@ class EmonADS1X15Sensor : public EmonSensor { #endif } last = millis(); + _error = SENSOR_ERROR_OK; } // Current value for slot # index double value(unsigned char index) { - - if (index < _count) { - - _error = SENSOR_ERROR_OK; - unsigned char port = index % _ports; - unsigned char magnitude = index / _ports; - - unsigned char i=0; - #if EMON_REPORT_CURRENT - if (magnitude == i++) return _current[port]; - #endif - #if EMON_REPORT_POWER - if (magnitude == i++) return _current[port] * _voltage; - #endif - #if EMON_REPORT_ENERGY - if (magnitude == i) return _energy[port]; - #endif - - } - - _error = SENSOR_ERROR_OUT_OF_RANGE; + unsigned char port = index % _ports; + unsigned char magnitude = index / _ports; + unsigned char i=0; + #if EMON_REPORT_CURRENT + if (magnitude == i++) return _current[port]; + #endif + #if EMON_REPORT_POWER + if (magnitude == i++) return _current[port] * _voltage; + #endif + #if EMON_REPORT_ENERGY + if (magnitude == i) return _energy[port]; + #endif return 0; - } protected: @@ -313,26 +301,8 @@ class EmonADS1X15Sensor : public EmonSensor { } config |= ((channel + 4) << 12); // Set single-ended input channel (0x4000 - 0x7000) - #if SENSOR_DEBUG - //Serial.printf("[EMON] ADS1X115 Config Registry: %04X\n", config); - #endif - // Write config register to the ADC - #if I2C_USE_BRZO - uint8_t buffer[3]; - buffer[0] = ADS1X15_REG_POINTER_CONFIG; - buffer[1] = config >> 8; - buffer[2] = config & 0xFF; - brzo_i2c_start_transaction(_address, I2C_SCL_FREQUENCY); - brzo_i2c_write(buffer, 3, false); - brzo_i2c_end_transaction(); - #else - Wire.beginTransmission(_address); - Wire.write((uint8_t) ADS1X15_REG_POINTER_CONFIG); - Wire.write((uint8_t) (config >> 8)); - Wire.write((uint8_t) (config & 0xFF)); - Wire.endTransmission(); - #endif + i2c_write_uint16(_address, ADS1X15_REG_POINTER_CONFIG, config); } @@ -344,7 +314,7 @@ class EmonADS1X15Sensor : public EmonSensor { setConfigRegistry(channel, true, false); setConfigRegistry(channel, false, false); setConfigRegistry(channel, false, true); - delay(10); + nice_delay(10); readADC(channel); previous = channel; } @@ -355,36 +325,11 @@ class EmonADS1X15Sensor : public EmonSensor { } unsigned int readADC(unsigned char channel) { - (void) channel; - - unsigned int value = 0; - - #if I2C_USE_BRZO - uint8_t buffer[3]; - buffer[0] = ADS1X15_REG_POINTER_CONVERT; - brzo_i2c_start_transaction(_address, I2C_SCL_FREQUENCY); - brzo_i2c_write(buffer, 1, false); - brzo_i2c_read(buffer, 2, false); - brzo_i2c_end_transaction(); - value |= buffer[0] << 8; - value |= buffer[1]; - - #else - Wire.beginTransmission(_address); - Wire.write(ADS1X15_REG_POINTER_CONVERT); - Wire.endTransmission(); - Wire.requestFrom(_address, (unsigned char) 2); - value |= Wire.read() << 8; - value |= Wire.read(); - #endif - + unsigned int value = i2c_read_uint16(_address, ADS1X15_REG_POINTER_CONVERT); if (_type = ADS1X15_CHIP_ADS1015) value >>= ADS1015_BIT_SHIFT; - delayMicroseconds(500); - return value; - } unsigned char _type = ADS1X15_CHIP_ADS1115; diff --git a/code/espurna/sensors/EmonAnalogSensor.h b/code/espurna/sensors/EmonAnalogSensor.h index 767825a3..e4041e93 100644 --- a/code/espurna/sensors/EmonAnalogSensor.h +++ b/code/espurna/sensors/EmonAnalogSensor.h @@ -1,12 +1,16 @@ // ----------------------------------------------------------------------------- // Energy Monitor Sensor using builtin ADC -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && EMON_ANALOG_SUPPORT #pragma once +// Set ADC to TOUT pin +#undef ADC_MODE_VALUE +#define ADC_MODE_VALUE ADC_TOUT + #include "Arduino.h" #include "EmonSensor.h" @@ -59,9 +63,13 @@ class EmonAnalogSensor : public EmonSensor { return String("EMON @ ANALOG @ GPIO0"); } + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String("0"); + } + // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; unsigned char i=0; #if EMON_REPORT_CURRENT if (index == i++) return MAGNITUDE_CURRENT; @@ -72,7 +80,6 @@ class EmonAnalogSensor : public EmonSensor { #if EMON_REPORT_ENERGY if (index == i) return MAGNITUDE_ENERGY; #endif - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } @@ -89,14 +96,13 @@ class EmonAnalogSensor : public EmonSensor { last = millis(); #endif + _error = SENSOR_ERROR_OK; + } // Current value for slot # index double value(unsigned char index) { - - _error = SENSOR_ERROR_OK; unsigned char channel = index / _magnitudes; - unsigned char i=0; #if EMON_REPORT_CURRENT if (index == i++) return _current[channel]; @@ -107,10 +113,7 @@ class EmonAnalogSensor : public EmonSensor { #if EMON_REPORT_ENERGY if (index == i) return _energy[channel]; #endif - - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; - } protected: diff --git a/code/espurna/sensors/EmonSensor.h b/code/espurna/sensors/EmonSensor.h index 8bb6eed4..527a4bda 100644 --- a/code/espurna/sensors/EmonSensor.h +++ b/code/espurna/sensors/EmonSensor.h @@ -1,14 +1,20 @@ // ----------------------------------------------------------------------------- // Abstract Energy Monitor Sensor (other EMON sensors extend this class) -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT #pragma once +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + #include "Arduino.h" #include "I2CSensor.h" +extern "C" { + #include "libs/fs_math.h" +} class EmonSensor : public I2CSensor { @@ -39,9 +45,16 @@ class EmonSensor : public I2CSensor { if (actual == 0) return; if (expected == actual) return; _current_ratio[channel] = _current_ratio[channel] * ((double) expected / (double) actual); + calculateFactors(channel); _dirty = true; } + void resetEnergy() { + for (unsigned char i=0; i<_channels; i++) { + _energy[i] = 0; + } + } + // --------------------------------------------------------------------- void setVoltage(double voltage) { @@ -60,6 +73,7 @@ class EmonSensor : public I2CSensor { if (channel >= _channels) return; if (_current_ratio[channel] == current_ratio) return; _current_ratio[channel] = current_ratio; + calculateFactors(channel); _dirty = true; } @@ -95,8 +109,7 @@ class EmonSensor : public I2CSensor { for (unsigned char i=0; i<_channels; i++) { _energy[i] = _current[i] = 0; _pivot[i] = _adc_counts >> 1; - _current_factor[i] = _current_ratio[i] * _reference / _adc_counts; - _multiplier[i] = calculateMultiplier(_current_factor[i]); + calculateFactors(i); } #if SENSOR_DEBUG @@ -109,6 +122,10 @@ class EmonSensor : public I2CSensor { } #endif + _ready = true; + _dirty = false; + + } protected: @@ -131,31 +148,36 @@ class EmonSensor : public I2CSensor { virtual unsigned int readADC(unsigned char channel) {} - unsigned int calculateMultiplier(double current_factor) { + void calculateFactors(unsigned char channel) { + + _current_factor[channel] = _current_ratio[channel] * _reference / _adc_counts; + unsigned int s = 1; unsigned int i = 1; unsigned int m = s * i; unsigned int multiplier; - while (m * current_factor < 1) { + while (m * _current_factor[channel] < 1) { multiplier = m; i = (i == 1) ? 2 : (i == 2) ? 5 : 1; if (i == 1) s *= 10; m = s * i; } - return multiplier; + _multiplier[channel] = multiplier; + } double read(unsigned char channel) { - int sample; int max = 0; int min = _adc_counts; - double filtered; double sum = 0; unsigned long time_span = millis(); for (unsigned long i=0; i<_samples; i++) { + int sample; + double filtered; + // Read analog value sample = readADC(channel); if (sample > max) max = sample; @@ -177,7 +199,7 @@ class EmonSensor : public I2CSensor { } // Calculate current - double rms = _samples > 0 ? sqrt(sum / _samples) : 0; + double rms = _samples > 0 ? fs_sqrt(sum / _samples) : 0; double current = _current_factor[channel] * rms; current = (double) (int(current * _multiplier[channel]) - 1) / _multiplier[channel]; if (current < 0) current = 0; @@ -191,7 +213,7 @@ class EmonSensor : public I2CSensor { DEBUG_MSG("[EMON] Min value: %d\n", min); DEBUG_MSG("[EMON] Midpoint value: %d\n", int(_pivot[channel])); DEBUG_MSG("[EMON] RMS value: %d\n", int(rms)); - DEBUG_MSG("[EMON] Current (mA): %d\n", int(current)); + DEBUG_MSG("[EMON] Current (mA): %d\n", int(1000 * current)); #endif // Check timing diff --git a/code/espurna/sensors/EventSensor.h b/code/espurna/sensors/EventSensor.h index c593be04..d46fc063 100644 --- a/code/espurna/sensors/EventSensor.h +++ b/code/espurna/sensors/EventSensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Event Counter Sensor -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && EVENTS_SUPPORT @@ -72,6 +72,7 @@ class EventSensor : public BaseSensor { void begin() { pinMode(_gpio, _mode); _enableInterrupts(true); + _ready = true; } // Descriptive name of the sensor @@ -81,23 +82,29 @@ class EventSensor : public BaseSensor { return String(buffer); } + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String(_gpio); + } + // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_EVENTS; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) { double value = _events; _events = 0; return value; }; - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } diff --git a/code/espurna/sensors/GUVAS12SDSensor.h b/code/espurna/sensors/GUVAS12SDSensor.h new file mode 100644 index 00000000..f188b2b3 --- /dev/null +++ b/code/espurna/sensors/GUVAS12SDSensor.h @@ -0,0 +1,174 @@ +// ----------------------------------------------------------------------------- +// GUVA-S12SD UV Sensor +// Copyright (C) 2017-2018 by Xose Pérez +// by Mustafa Tufan +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && GUVAS12SD_SUPPORT + +#pragma once + +// Set ADC to TOUT pin +#undef ADC_MODE_VALUE +#define ADC_MODE_VALUE ADC_TOUT + +#include "Arduino.h" +#include "BaseSensor.h" + +// http://www.eoc-inc.com/genicom/GUVA-S12SD.pdf +// +// GUVA-S12D has a wide spectral range of 200nm-400nm +// The output voltage and the UV index is linear, illumination intensity = 307 * Vsig where: Vsig is the value of voltage measured from the SIG pin of the interface, unit V. +// illumination intensity unit: mW/m2 for the combination strength of UV light with wavelength range: 200nm-400nm +// UV Index = illumination intensity / 200 +// +// UV Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 10+ +// -----------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-------- +// mV | <50 | 227 | 318 | 408 | 503 | 606 | 696 | 795 | 881 | 976 | 1079 | 1170+ +// analog val | <10 | 46 | 65 | 83 | 103 | 124 | 142 | 162 | 180 | 200 | 221 | 240+ +// + +#define UV_SAMPLE_RATE 1 + +class GUVAS12SDSensor : public BaseSensor { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + GUVAS12SDSensor(): BaseSensor() { + _count = 1; + _sensor_id = SENSOR_GUVAS12SD_ID; + } + + ~GUVAS12SDSensor() { + if (_previous != GPIO_NONE) gpioReleaseLock(_previous); + } + + // --------------------------------------------------------------------- + + void setGPIO(unsigned char gpio) { + _gpio = gpio; + } + + // --------------------------------------------------------------------- + + unsigned char getGPIO() { + return _gpio; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + + // Manage GPIO lock + if (_previous != GPIO_NONE) gpioReleaseLock(_previous); + _previous = GPIO_NONE; + if (!gpioGetLock(_gpio)) { + _error = SENSOR_ERROR_GPIO_USED; + return; + } + _previous = _gpio; + + _ready = true; + + } + + // Pre-read hook (usually to populate registers with up-to-date data) + void pre() { + _error = SENSOR_ERROR_OK; + _read(); + } + + // Descriptive name of the sensor + String description() { + char buffer[18]; + snprintf(buffer, sizeof(buffer), "GUVAS12SD @ GPIO%d", _gpio); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String(_gpio); + } + + // Type for slot # index + unsigned char type(unsigned char index) { + if (index == 0) return MAGNITUDE_UV; + return MAGNITUDE_NONE; + } + + // Current value for slot # index + double value(unsigned char index) { + if (index == 0) return _uvindex; + return 0; + } + + + protected: + + // --------------------------------------------------------------------- + // Protected + // --------------------------------------------------------------------- + + void _read() { + + int _average = 0; + + #if UV_SAMPLE_RATE == 1 + _average = analogRead(0); + #else + for (unsigned int i=0; i < UV_SAMPLE_RATE; i++) { + _average += analogRead(0); + nice_delay(2); + } + _average = (_average / UV_SAMPLE_RATE); + #endif + // _sensormV = _average / 1023*3.3; + + if (_average < 10) { + _uvindex = 0; + } else if (_average < 46) { + _uvindex = (_average - 10) / (46-10); + } else if (_average < 65) { + _uvindex = 1 + ((_average - 46) / (65-46)); + } else if (_average < 83) { + _uvindex = 2 + ((_average - 65) / (83-65)); + } else if (_average < 103) { + _uvindex = 3 + ((_average - 83) / (103- 83)); + } else if (_average < 124) { + _uvindex = 4 + ((_average - 103) / (124-103)); + } else if (_average < 142) { + _uvindex = 5 + ((_average - 124) / (142-124)); + } else if (_average < 162) { + _uvindex = 6 + ((_average - 142) / (162-142)); + } else if (_average < 180) { + _uvindex = 7 + ((_average - 162) / (180-162)); + } else if (_average < 200) { + _uvindex = 8 + ((_average - 180) / (200-180)); + } else if (_average < 221) { + _uvindex = 9 + ((_average - 200) / (221-200)); + } else { + _uvindex = 10; + } + + } + + unsigned char _gpio = GPIO_NONE; + unsigned char _previous = GPIO_NONE; + + double _uvindex = 0; + +}; + +#endif // SENSOR_SUPPORT && GUVAS12SD_SUPPORT diff --git a/code/espurna/sensors/GeigerSensor.h b/code/espurna/sensors/GeigerSensor.h new file mode 100644 index 00000000..7165ed61 --- /dev/null +++ b/code/espurna/sensors/GeigerSensor.h @@ -0,0 +1,298 @@ +// ----------------------------------------------------------------------------- +// Geiger Sensor based on Event Counter Sensor +// Copyright (C) 2018 by Sven Kopetzki +// Documentation: https://github.com/Trickx/espurna/wiki/Geiger-counter +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && GEIGER_SUPPORT + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" + +class GeigerSensor : public BaseSensor { + +public: + +// --------------------------------------------------------------------- +// Public +// --------------------------------------------------------------------- + +GeigerSensor() : BaseSensor() { + _count = 2; + _sensor_id = SENSOR_GEIGER_ID; +} + +~GeigerSensor() { + _enableInterrupts(false); +} + +// --------------------------------------------------------------------- + +void setGPIO(unsigned char gpio) { + _gpio = gpio; +} + +void setMode(unsigned char mode) { + _mode = mode; +} + +void setInterruptMode(unsigned char mode) { + _interrupt_mode = mode; +} + +void setDebounceTime(unsigned long debounce) { + _debounce = debounce; +} + +void setCPM2SievertFactor(unsigned int cpm2sievert) { + _cpm2sievert = cpm2sievert; +} + +// --------------------------------------------------------------------- + +unsigned char getGPIO() { + return _gpio; +} + +unsigned char getMode() { + return _mode; +} + +unsigned char getInterruptMode() { + return _interrupt_mode; +} + +unsigned long getDebounceTime() { + return _debounce; +} + +unsigned long getCPM2SievertFactor() { + return _cpm2sievert; +} + +// --------------------------------------------------------------------- +// Sensors API +// --------------------------------------------------------------------- + +// Initialization method, must be idempotent +// Defined outside the class body +void begin() { + pinMode(_gpio, _mode); + _enableInterrupts(true); + _ready = true; +} + +// Descriptive name of the sensor +String description() { + char buffer[20]; + snprintf(buffer, sizeof(buffer), "µSv/h @ GPIO%d", _gpio); + return String(buffer); +} + +// Descriptive name of the slot # index +String slot(unsigned char index) { + char buffer[30]; + unsigned char i=0; + #if GEIGER_REPORT_CPM + if (index == i++) { + snprintf(buffer, sizeof(buffer), "Counts per Minute @ GPIO%d", _gpio); + return String(buffer); + } + #endif + #if GEIGER_REPORT_SIEVERTS + if (index == i++) { + snprintf(buffer, sizeof(buffer), "CPM / %d = µSv/h", _cpm2sievert); + return String(buffer); + } + #endif + snprintf(buffer, sizeof(buffer), "Events @ GPIO%d", _gpio); + return String(buffer); +}; + +// Address of the sensor (it could be the GPIO or I2C address) +String address(unsigned char index) { + return String(_gpio); +} + +// Type for slot # index +unsigned char type(unsigned char index) { + unsigned char i=0; + #if GEIGER_REPORT_CPM + if (index == i++) return MAGNITUDE_GEIGER_CPM; + #endif + #if GEIGER_REPORT_SIEVERTS + if (index == i++) return MAGNITUDE_GEIGER_SIEVERT; + #endif + return MAGNITUDE_NONE; +} + +// Current value for slot # index +double value(unsigned char index) { + unsigned char i=0; + #if GEIGER_REPORT_CPM + if (index == i++) { + unsigned long _period_begin = _lastreport_cpm; + _lastreport_cpm = millis(); + double value = _events * 60000; + value = value / (_lastreport_cpm-_period_begin); + #if SENSOR_DEBUG + char data[128]; char buffer[10]; + dtostrf(value, 1-sizeof(buffer), 4, buffer); + snprintf(data, sizeof(data), "Ticks: %u | Interval: %u | CPM: %s", _ticks, (_lastreport_cpm-_period_begin), buffer); + DEBUG_MSG("[GEIGER] %s\n", data); + #endif + _events = 0; + return value; + } + #endif + #if GEIGER_REPORT_SIEVERTS + if (index == i++) { + unsigned long _period_begin = _lastreport_sv; + _lastreport_sv = millis(); + double value = _ticks * 60000 / _cpm2sievert; + value = value / (_lastreport_sv-_period_begin); + #if SENSOR_DEBUG + char data[128]; char buffer[10]; + dtostrf(value, 1-sizeof(buffer), 4, buffer); + snprintf(data, sizeof(data), "Ticks: %u | Interval: %u | µSievert: %s", _ticks, (_lastreport_sv-_period_begin), buffer); + DEBUG_MSG("[GEIGER] %s\n", data); + #endif + _ticks = 0; + return value; + } + #endif + return 0; +} + + +// Handle interrupt calls +void handleInterrupt(unsigned char gpio) { + (void) gpio; + static unsigned long last = 0; + if (millis() - last > _debounce) { + _events = _events + 1; + _ticks = _ticks + 1; + last = millis(); + } +} + +protected: + +// --------------------------------------------------------------------- +// Interrupt management +// --------------------------------------------------------------------- + +void _attach(GeigerSensor * instance, unsigned char gpio, unsigned char mode); +void _detach(unsigned char gpio); + +void _enableInterrupts(bool value) { + + static unsigned char _interrupt_gpio = GPIO_NONE; + + if (value) { + if (_interrupt_gpio != GPIO_NONE) _detach(_interrupt_gpio); + _attach(this, _gpio, _interrupt_mode); + _interrupt_gpio = _gpio; + } else if (_interrupt_gpio != GPIO_NONE) { + _detach(_interrupt_gpio); + _interrupt_gpio = GPIO_NONE; + } + +} + +// --------------------------------------------------------------------- +// Protected +// --------------------------------------------------------------------- + +volatile unsigned long _events = 0; +volatile unsigned long _ticks = 0; + +unsigned long _debounce = GEIGER_DEBOUNCE; +unsigned int _cpm2sievert = GEIGER_CPM2SIEVERT; +unsigned char _gpio; +unsigned char _mode; +unsigned char _interrupt_mode; + +// Added for µSievert calculations +unsigned long _lastreport_cpm = millis(); +unsigned long _lastreport_sv = _lastreport_cpm; + +}; + +// ----------------------------------------------------------------------------- +// Interrupt helpers +// ----------------------------------------------------------------------------- + +GeigerSensor * _geiger_sensor_instance[10] = {NULL}; + +void ICACHE_RAM_ATTR _geiger_sensor_isr(unsigned char gpio) { + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_geiger_sensor_instance[index]) { + _geiger_sensor_instance[index]->handleInterrupt(gpio); + } +} + +void ICACHE_RAM_ATTR _geiger_sensor_isr_0() { + _geiger_sensor_isr(0); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_1() { + _geiger_sensor_isr(1); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_2() { + _geiger_sensor_isr(2); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_3() { + _geiger_sensor_isr(3); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_4() { + _geiger_sensor_isr(4); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_5() { + _geiger_sensor_isr(5); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_12() { + _geiger_sensor_isr(12); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_13() { + _geiger_sensor_isr(13); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_14() { + _geiger_sensor_isr(14); +} +void ICACHE_RAM_ATTR _geiger_sensor_isr_15() { + _geiger_sensor_isr(15); +} + +static void (*_geiger_sensor_isr_list[10])() = { + _geiger_sensor_isr_0, _geiger_sensor_isr_1, _geiger_sensor_isr_2, + _geiger_sensor_isr_3, _geiger_sensor_isr_4, _geiger_sensor_isr_5, + _geiger_sensor_isr_12, _geiger_sensor_isr_13, _geiger_sensor_isr_14, + _geiger_sensor_isr_15 +}; + +void GeigerSensor::_attach(GeigerSensor * instance, unsigned char gpio, unsigned char mode) { + if (!gpioValid(gpio)) return; + _detach(gpio); + unsigned char index = gpio > 5 ? gpio-6 : gpio; + _geiger_sensor_instance[index] = instance; + attachInterrupt(gpio, _geiger_sensor_isr_list[index], mode); + #if SENSOR_DEBUG + DEBUG_MSG_P(PSTR("[GEIGER] GPIO%d interrupt attached to %s\n"), gpio, instance->description().c_str()); + #endif +} + +void GeigerSensor::_detach(unsigned char gpio) { + if (!gpioValid(gpio)) return; + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_geiger_sensor_instance[index]) { + detachInterrupt(gpio); + #if SENSOR_DEBUG + DEBUG_MSG_P(PSTR("[GEIGER] GPIO%d interrupt detached from %s\n"), gpio, _geiger_sensor_instance[index]->description().c_str()); + #endif + _geiger_sensor_instance[index] = NULL; + } +} + +#endif // SENSOR_SUPPORT && GEIGER_SUPPORT diff --git a/code/espurna/sensors/HCSR04Sensor.h b/code/espurna/sensors/HCSR04Sensor.h new file mode 100644 index 00000000..d2901000 --- /dev/null +++ b/code/espurna/sensors/HCSR04Sensor.h @@ -0,0 +1,119 @@ +// ----------------------------------------------------------------------------- +// HC-SR04 Ultrasonic sensor +// Copyright (C) 2018 by Xose Pérez +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && HCSR04_SUPPORT + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" + +class HCSR04Sensor : public BaseSensor { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + HCSR04Sensor(): BaseSensor() { + _count = 1; + _sensor_id = SENSOR_HCSR04_ID; + } + + // --------------------------------------------------------------------- + + void setEcho(unsigned char echo) { + _echo = echo; + } + + void setTrigger(unsigned char trigger) { + _trigger = trigger; + } + + // --------------------------------------------------------------------- + + unsigned char getEcho() { + return _echo; + } + + unsigned char getTrigger() { + return _trigger; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + pinMode(_echo, INPUT); + pinMode(_trigger, OUTPUT); + digitalWrite(_trigger, LOW); + _ready = true; + } + + // Descriptive name of the sensor + String description() { + char buffer[24]; + snprintf(buffer, sizeof(buffer), "HCSR04 @ GPIO(%u, %u)", _trigger, _echo); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String(_trigger); + } + + // Type for slot # index + unsigned char type(unsigned char index) { + if (index == 0) return MAGNITUDE_DISTANCE; + return MAGNITUDE_NONE; + } + + // Current value for slot # 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; + + } + + return 0; + + } + + + protected: + + // --------------------------------------------------------------------- + // Protected + // --------------------------------------------------------------------- + + unsigned char _trigger; + unsigned char _echo; + +}; + +#endif // SENSOR_SUPPORT && HCSR04_SUPPORT diff --git a/code/espurna/sensors/HLW8012Sensor.h b/code/espurna/sensors/HLW8012Sensor.h index 5a45241c..be21118f 100644 --- a/code/espurna/sensors/HLW8012Sensor.h +++ b/code/espurna/sensors/HLW8012Sensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // Event Counter Sensor -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && HLW8012_SUPPORT @@ -48,6 +48,10 @@ class HLW8012Sensor : public BaseSensor { _hlw8012->resetMultipliers(); } + void resetEnergy() { + _hlw8012->resetEnergy(); + } + // --------------------------------------------------------------------- void setSEL(unsigned char sel) { @@ -153,18 +157,31 @@ class HLW8012Sensor : public BaseSensor { }); #endif + _ready = true; + } // Descriptive name of the sensor String description() { char buffer[25]; - snprintf(buffer, sizeof(buffer), "HLW8012 @ GPIO(%i,%i,%i)", _sel, _cf, _cf1); + snprintf(buffer, sizeof(buffer), "HLW8012 @ GPIO(%u,%u,%u)", _sel, _cf, _cf1); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[10]; + snprintf(buffer, sizeof(buffer), "%u:%u:%u", _sel, _cf, _cf1); return String(buffer); } // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_CURRENT; if (index == 1) return MAGNITUDE_VOLTAGE; if (index == 2) return MAGNITUDE_POWER_ACTIVE; @@ -172,13 +189,11 @@ class HLW8012Sensor : public BaseSensor { if (index == 4) return MAGNITUDE_POWER_APPARENT; if (index == 5) return MAGNITUDE_POWER_FACTOR; if (index == 6) return MAGNITUDE_ENERGY; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return _hlw8012->getCurrent(); if (index == 1) return _hlw8012->getVoltage(); if (index == 2) return _hlw8012->getActivePower(); @@ -186,7 +201,6 @@ class HLW8012Sensor : public BaseSensor { if (index == 4) return _hlw8012->getApparentPower(); if (index == 5) return 100 * _hlw8012->getPowerFactor(); if (index == 6) return _hlw8012->getEnergy(); - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } @@ -243,10 +257,10 @@ class HLW8012Sensor : public BaseSensor { // --------------------------------------------------------------------- - unsigned char _sel; - unsigned char _cf; - unsigned char _cf1; - bool _sel_current; + unsigned char _sel = GPIO_NONE; + unsigned char _cf = GPIO_NONE; + unsigned char _cf1 = GPIO_NONE; + bool _sel_current = true; HLW8012 * _hlw8012 = NULL; @@ -295,7 +309,7 @@ void HLW8012Sensor::_attach(HLW8012Sensor * instance, unsigned char gpio, unsign _hlw8012_sensor_instance[index] = instance; attachInterrupt(gpio, _hlw8012_sensor_isr_list[index], mode); #if SENSOR_DEBUG - DEBUG_MSG_P(PSTR("[SENSOR] GPIO%d interrupt attached to %s\n"), gpio, instance->description().c_str()); + DEBUG_MSG_P(PSTR("[SENSOR] GPIO%u interrupt attached to %s\n"), gpio, instance->description().c_str()); #endif } @@ -305,7 +319,7 @@ void HLW8012Sensor::_detach(unsigned char gpio) { if (_hlw8012_sensor_instance[index]) { detachInterrupt(gpio); #if SENSOR_DEBUG - DEBUG_MSG_P(PSTR("[SENSOR] GPIO%d interrupt detached from %s\n"), gpio, _hlw8012_sensor_instance[index]->description().c_str()); + DEBUG_MSG_P(PSTR("[SENSOR] GPIO%u interrupt detached from %s\n"), gpio, _hlw8012_sensor_instance[index]->description().c_str()); #endif _hlw8012_sensor_instance[index] = NULL; } diff --git a/code/espurna/sensors/I2CSensor.h b/code/espurna/sensors/I2CSensor.h index f4391d03..3b1b8ae6 100644 --- a/code/espurna/sensors/I2CSensor.h +++ b/code/espurna/sensors/I2CSensor.h @@ -1,10 +1,28 @@ // ----------------------------------------------------------------------------- // Abstract I2C sensor class (other sensor classes extend this class) -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && ( I2C_SUPPORT || EMON_ANALOG_SUPPORT ) +#if I2C_USE_BRZO + #define I2C_TRANS_SUCCESS 0 // All i2c commands were executed without errors + #define I2C_TRANS_ERROR_BUS_NOT_FREE 1 // Bus not free, i.e. either SDA or SCL is low + #define I2C_TRANS_ERROR_NACK_WRITE 2 // Not ACK ("NACK") by slave during write: + // Either the slave did not respond to the given slave address; or the slave did not ACK a byte transferred by the master. + #define I2C_TRANS_ERROR_NACK_READ 4 // Not ACK ("NACK") by slave during read, + // i.e. slave did not respond to the given slave address + #define I2C_TRANS_ERROR_CLOCK 8 // Clock Stretching by slave exceeded maximum clock stretching time. Most probably, there is a bus stall now! + #define I2C_TRANS_ERROR_READ_NULL 16 // Read was called with 0 bytes to be read by the master. Command not sent to the slave, since this could yield to a bus stall + #define I2C_TRANS_ERROR_TIMEOUT 32 // ACK Polling timeout exceeded +#else // Wire + #define I2C_TRANS_SUCCESS 0 // success + #define I2C_TRANS_ERROR_BUFFER_OVERLOW 1 // data too long to fit in transmit buffer + #define I2C_TRANS_ERROR_NACK_ADDRESS 2 // received NACK on transmit of address + #define I2C_TRANS_ERROR_NACK_DATA 3 // received NACK on transmit of data + #define I2C_TRANS_ERROR_OTHER 4 // other error +#endif + #pragma once #include "BaseSensor.h" @@ -23,33 +41,49 @@ class I2CSensor : public BaseSensor { return _address; } + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[5]; + snprintf(buffer, sizeof(buffer), "0x%02X", _address); + return String(buffer); + } + protected: // Specific for I2C sensors unsigned char _begin_i2c(unsigned char address, size_t size, unsigned char * addresses) { + // If we have already locked this address for this sensor quit + if ((address > 0) && (address == _previous_address)) { + return _previous_address; + } + // Check if we should release a previously locked address - if (_previous_address != address) { + if ((_previous_address > 0) && (_previous_address != address)) { i2cReleaseLock(_previous_address); + _previous_address = 0; } - // If we have already an address, check it is not locked - if (address && !i2cGetLock(address)) { - _error = SENSOR_ERROR_I2C; - - // If we don't have an address... - } else { - - // Trigger auto-discover - address = i2cFindAndLock(size, addresses); + // If requesting a specific address, try to ger a lock to it + if ((0 < address) && i2cGetLock(address)) { + _previous_address = address; + return _previous_address; + } - // If still nothing exit with error - if (address == 0) _error = SENSOR_ERROR_I2C; + // If everything else fails, perform an auto-discover + _previous_address = i2cFindAndLock(size, addresses); + // Flag error + if (0 == _previous_address) { + _error = SENSOR_ERROR_I2C; } - _previous_address = address; - return address; + return _previous_address; } diff --git a/code/espurna/sensors/MHZ19Sensor.h b/code/espurna/sensors/MHZ19Sensor.h index 576d649b..105adf22 100644 --- a/code/espurna/sensors/MHZ19Sensor.h +++ b/code/espurna/sensors/MHZ19Sensor.h @@ -3,7 +3,7 @@ // Based on: https://github.com/nara256/mhz19_uart // http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf // Uses SoftwareSerial library -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && MHZ19_SUPPORT @@ -72,28 +72,41 @@ class MHZ19Sensor : public BaseSensor { void begin() { if (!_dirty) return; - _dirty = false; if (_serial) delete _serial; - _serial = new SoftwareSerial(_pin_rx, _pin_tx, false, 256); + _serial = new SoftwareSerial(_pin_rx, _pin_tx, false, 32); + _serial->enableIntTx(false); _serial->begin(9600); calibrateAuto(false); + _ready = true; + _dirty = false; + } // Descriptive name of the sensor String description() { char buffer[28]; - snprintf(buffer, sizeof(buffer), "MHZ19 @ SwSerial(%i,%i)", _pin_rx, _pin_tx); + snprintf(buffer, sizeof(buffer), "MHZ19 @ SwSerial(%u,%u)", _pin_rx, _pin_tx); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[6]; + snprintf(buffer, sizeof(buffer), "%u:%u", _pin_rx, _pin_tx); return String(buffer); } // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_CO2; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } @@ -103,9 +116,7 @@ class MHZ19Sensor : public BaseSensor { // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return _co2; - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } @@ -185,6 +196,8 @@ class MHZ19Sensor : public BaseSensor { _error = SENSOR_ERROR_OUT_OF_RANGE; } + } else { + _error = SENSOR_ERROR_CRC; } } diff --git a/code/espurna/sensors/PMSX003Sensor.h b/code/espurna/sensors/PMSX003Sensor.h index e6a3aada..9f6ddd4b 100644 --- a/code/espurna/sensors/PMSX003Sensor.h +++ b/code/espurna/sensors/PMSX003Sensor.h @@ -1,7 +1,8 @@ // ----------------------------------------------------------------------------- -// PMSX003 Dust Sensor +// PMS Dust Sensor // Uses SoftwareSerial library // Contribution by Òscar Rovira López +// Refine to support PMS5003T/PMS5003ST by Yonsm Guo // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && PMSX003_SUPPORT @@ -11,10 +12,141 @@ #include "Arduino.h" #include "BaseSensor.h" -#include #include -class PMSX003Sensor : public BaseSensor { +// Type of sensor +#define PMS_TYPE_X003 0 +#define PMS_TYPE_X003_9 1 +#define PMS_TYPE_5003T 2 +#define PMS_TYPE_5003ST 3 + +// Sensor type specified data +#define PMS_SLOT_MAX 4 +#define PMS_DATA_MAX 17 +const static struct { + const char *name; + unsigned char data_count; + unsigned char slot_count; + unsigned char slot_types[PMS_SLOT_MAX]; +} pms_specs[] = { + {"PMSX003", 13, 3, {MAGNITUDE_PM1dot0, MAGNITUDE_PM2dot5, MAGNITUDE_PM10}}, + {"PMSX003_9", 9, 3, {MAGNITUDE_PM1dot0, MAGNITUDE_PM2dot5, MAGNITUDE_PM10}}, + {"PMS5003T", 13, 3, {MAGNITUDE_PM2dot5, MAGNITUDE_TEMPERATURE, MAGNITUDE_HUMIDITY}}, + {"PMS5003ST", 17, 4, {MAGNITUDE_PM2dot5, MAGNITUDE_TEMPERATURE, MAGNITUDE_HUMIDITY, MAGNITUDE_HCHO}} +}; + +// [MAGIC][LEN][DATA9|13|17][SUM] +#define PMS_PACKET_SIZE(data_count) ((data_count + 3) * 2) +#define PMS_PAYLOAD_SIZE(data_count) ((data_count + 1) * 2) + + +// PMS sensor utils +// Command functions copied from: https://github.com/fu-hsi/PMS/blob/master/src/PMS.cpp +// Reading function is rewrited to support flexible reading for PMS5003T/PMS5003ST +class PMSX003 { + + protected: + SoftwareSerial *_serial = NULL; // Should initialized by child class + + public: + + // Standby mode. For low power consumption and prolong the life of the sensor. + inline void sleep() { + uint8_t command[] = { 0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73 }; + _serial->write(command, sizeof(command)); + } + + // Operating mode. Stable data should be got at least 30 seconds after the sensor wakeup from the sleep mode because of the fan's performance. + inline void wakeUp() { + uint8_t command[] = { 0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74 }; + _serial->write(command, sizeof(command)); + } + + // Active mode. Default mode after power up. In this mode sensor would send serial data to the host automatically. + inline void activeMode() { + uint8_t command[] = { 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71 }; + _serial->write(command, sizeof(command)); + } + + // Passive mode. In this mode, sensor would send serial data to the host only for request. + inline void passiveMode() { + uint8_t command[] = { 0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70 }; + _serial->write(command, sizeof(command)); + } + + // Request read, ONLY needed in Passive Mode!! + inline void requestRead() { + uint8_t command[] = { 0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71 }; + _serial->write(command, sizeof(command)); + } + + // Read sensor's data + bool readData(uint16_t data[], unsigned char data_count) { + + do { + + int avail = _serial->available(); + #if SENSOR_DEBUG + //debugSend("[SENSOR] PMS: Packet available = %d\n", avail); + #endif + if (avail < PMS_PACKET_SIZE(data_count)) { + break; + } + + if (_serial->read() == 0x42 && _serial->read() == 0x4D) { + + uint16_t sum = 0x42 + 0x4D; + uint16_t size = read16(sum); + if (size != PMS_PAYLOAD_SIZE(data_count)) { + #if SENSOR_DEBUG + debugSend(("[SENSOR] PMS: Payload size: %d != %d.\n"), size, PMS_PAYLOAD_SIZE(data_count)); + #endif + break; + } + + for (int i = 0; i < data_count; i++) { + data[i] = read16(sum); + #if SENSOR_DEBUG + //debugSend(("[SENSOR] PMS: data[%d] = %d\n"), i, data[i]); + #endif + } + + uint16_t checksum = read16(); + if (sum == checksum) { + return true; + } else { + #if SENSOR_DEBUG + debugSend(("[SENSOR] PMS checksum: %04X != %04X\n"), sum, checksum); + #endif + } + break; + } + + } while (true); + + return false; + + } + + private: + + // Read 16-bit + inline uint16_t read16() { + return ((uint16_t) _serial->read()) << 8 | _serial->read(); + } + + // Read 16-bit and calculate checksum + uint16_t read16(uint16_t &checksum) { + uint8_t high = _serial->read(); + uint8_t low = _serial->read(); + checksum += high; + checksum += low; + return ((uint16_t) high) << 8 | low; + } + +}; + +class PMSX003Sensor : public BaseSensor, PMSX003 { public: @@ -23,13 +155,12 @@ class PMSX003Sensor : public BaseSensor { // --------------------------------------------------------------------- PMSX003Sensor(): BaseSensor() { - _count = 3; + _count = pms_specs[_type].slot_count; _sensor_id = SENSOR_PMSX003_ID; } ~PMSX003Sensor() { if (_serial) delete _serial; - if (_pms) delete _pms; } void setRX(unsigned char pin_rx) { @@ -44,6 +175,12 @@ class PMSX003Sensor : public BaseSensor { _dirty = true; } + // Should call setType after constrcutor immediately to enable corresponding slot count + void setType(unsigned char type) { + _type = type; + _count = pms_specs[_type].slot_count; + } + // --------------------------------------------------------------------- unsigned char getRX() { @@ -54,6 +191,10 @@ class PMSX003Sensor : public BaseSensor { return _pin_tx; } + unsigned char getType() { + return _type; + } + // --------------------------------------------------------------------- // Sensor API // --------------------------------------------------------------------- @@ -62,51 +203,44 @@ class PMSX003Sensor : public BaseSensor { void begin() { if (!_dirty) return; - _dirty = false; if (_serial) delete _serial; - if (_pms) delete _pms; - _serial = new SoftwareSerial(_pin_rx, _pin_tx, false, 256); + _serial = new SoftwareSerial(_pin_rx, _pin_tx, false, 64); + _serial->enableIntTx(false); _serial->begin(9600); - _pms = new PMS(* _serial); - _pms->passiveMode(); + passiveMode(); _startTime = millis(); + _ready = true; + _dirty = false; } // Descriptive name of the sensor String description() { char buffer[28]; - snprintf(buffer, sizeof(buffer), "PMSX003 @ SwSerial(%i,%i)", _pin_rx, _pin_tx); + snprintf(buffer, sizeof(buffer), "%s @ SwSerial(%u,%u)", pms_specs[_type].name, _pin_rx, _pin_tx); return String(buffer); } // Descriptive name of the slot # index String slot(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - char buffer[36]; - if (index == 0) snprintf(buffer, sizeof(buffer), "PM1.0 @ PMSX003 @ SwSerial(%i,%i)", _pin_rx, _pin_tx); - if (index == 1) snprintf(buffer, sizeof(buffer), "PM2.5 @ PMSX003 @ SwSerial(%i,%i)", _pin_rx, _pin_tx); - if (index == 2) snprintf(buffer, sizeof(buffer), "PM10 @ PMSX003 @ SwSerial(%i,%i)", _pin_rx, _pin_tx); - return String(buffer); - } - _error = SENSOR_ERROR_OUT_OF_RANGE; - return String(); + char buffer[36] = {0}; + snprintf(buffer, sizeof(buffer), "%d @ %s @ SwSerial(%u,%u)", int(index + 1), pms_specs[_type].name, _pin_rx, _pin_tx); + return String(buffer); + } + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[6]; + snprintf(buffer, sizeof(buffer), "%u:%u", _pin_rx, _pin_tx); + return String(buffer); } // Type for slot # index unsigned char type(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - if (index == 0) return MAGNITUDE_PM1dot0; - if (index == 1) return MAGNITUDE_PM2dot5; - if (index == 2) return MAGNITUDE_PM10; - } - _error = SENSOR_ERROR_OUT_OF_RANGE; - return MAGNITUDE_NONE; + return pms_specs[_type].slot_types[index]; } void pre() { @@ -118,39 +252,74 @@ class PMSX003Sensor : public BaseSensor { _error = SENSOR_ERROR_OK; - if(_pms->read(_data)) { - _pm1dot0 = _data.PM_AE_UG_1_0; - _pm2dot5 = _data.PM_AE_UG_2_5; - _pm10 = _data.PM_AE_UG_10_0; + #if PMS_SMART_SLEEP + unsigned int readCycle; + if (_readCount++ > 30) { + readCycle = _readCount % 30; + if (readCycle == 0) { + #if SENSOR_DEBUG + debugSend("[SENSOR] %s: Wake up: %d\n", pms_specs[_type].name, _readCount); + #endif + wakeUp(); + return; + } else if (readCycle == 1) { + requestRead(); + } else if (readCycle > 6) { + return; + } + } else { + readCycle = -1; + } + #endif + + uint16_t data[PMS_DATA_MAX]; + if (readData(data, pms_specs[_type].data_count)) { + if (_type == PMS_TYPE_5003ST) { + _slot_values[0] = data[4]; + _slot_values[1] = (double)data[13] / 10; + _slot_values[2] = (double)data[14] / 10; + _slot_values[3] = (double)data[12] / 1000; + } else if (_type == PMS_TYPE_5003T) { + _slot_values[0] = data[4]; + _slot_values[1] = (double)data[10] / 10; + _slot_values[2] = (double)data[11] / 10; + } else { + _slot_values[0] = data[3]; + _slot_values[1] = data[4]; + _slot_values[2] = data[5]; + } } - _pms->requestRead(); - + #if PMS_SMART_SLEEP + if (readCycle == 6) { + sleep(); + #if SENSOR_DEBUG + debugSend("[SENSOR] %s: Enter sleep mode: %d\n", pms_specs[_type].name, _readCount); + #endif + return; + } + #endif + + requestRead(); + } // Current value for slot # index double value(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - if(index == 0) return _pm1dot0; - if(index == 1) return _pm2dot5; - if(index == 2) return _pm10; - } - _error = SENSOR_ERROR_OUT_OF_RANGE; - return 0; + return _slot_values[index]; } protected: - unsigned int _pm1dot0; - unsigned int _pm2dot5; - unsigned int _pm10; unsigned int _pin_rx; unsigned int _pin_tx; unsigned long _startTime; - SoftwareSerial * _serial = NULL; - PMS * _pms = NULL; - PMS::DATA _data; + unsigned char _type = PMS_TYPE_X003; + double _slot_values[PMS_SLOT_MAX] = {0}; + + #if PMS_SMART_SLEEP + unsigned int _readCount = 0; + #endif }; -#endif // SENSOR_SUPPORT && PMSX003_SUPPORT +#endif // SENSOR_SUPPORT && PMS_SUPPORT diff --git a/code/espurna/sensors/PZEM004TSensor.h b/code/espurna/sensors/PZEM004TSensor.h new file mode 100644 index 00000000..29635fd6 --- /dev/null +++ b/code/espurna/sensors/PZEM004TSensor.h @@ -0,0 +1,133 @@ +// ----------------------------------------------------------------------------- +// PZEM004T based power monitor +// Copyright (C) 2018 by Xose Pérez +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && PZEM004T_SUPPORT + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" + +#include + +class PZEM004TSensor : public BaseSensor { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + PZEM004TSensor(): BaseSensor() { + _count = 4; + _sensor_id = SENSOR_PZEM004T_ID; + _ip = IPAddress(192,168,1,1); + } + + ~PZEM004TSensor() { + if (_pzem) delete _pzem; + } + + // --------------------------------------------------------------------- + + void setRX(unsigned char pin_rx) { + if (_pin_rx == pin_rx) return; + _pin_rx = pin_rx; + _dirty = true; + } + + void setTX(unsigned char pin_tx) { + if (_pin_tx == pin_tx) return; + _pin_tx = pin_tx; + _dirty = true; + } + + void setSerial(HardwareSerial * serial) { + _serial = serial; + _dirty = true; + } + + // --------------------------------------------------------------------- + + unsigned char getRX() { + return _pin_rx; + } + + unsigned char getTX() { + return _pin_tx; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + + if (!_dirty) return; + + if (_pzem) delete _pzem; + if (_serial) { + _pzem = new PZEM004T(_serial); + } else { + _pzem = new PZEM004T(_pin_rx, _pin_tx); + } + _pzem->setAddress(_ip); + + _ready = true; + _dirty = false; + + } + + // Descriptive name of the sensor + String description() { + char buffer[28]; + snprintf(buffer, sizeof(buffer), "PZEM004T @ SwSerial(%u,%u)", _pin_rx, _pin_tx); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return _ip.toString(); + } + + // Type for slot # index + unsigned char type(unsigned char index) { + if (index == 0) return MAGNITUDE_CURRENT; + if (index == 1) return MAGNITUDE_VOLTAGE; + if (index == 2) return MAGNITUDE_POWER_ACTIVE; + if (index == 3) return MAGNITUDE_ENERGY; + return MAGNITUDE_NONE; + } + + // Current value for slot # index + double value(unsigned char index) { + if (index == 0) return _pzem->current(_ip); + if (index == 1) return _pzem->voltage(_ip); + if (index == 2) return _pzem->power(_ip); + if (index == 3) return _pzem->energy(_ip); + return 0; + } + + protected: + + // --------------------------------------------------------------------- + // Protected + // --------------------------------------------------------------------- + + unsigned int _pin_rx = PZEM004T_RX_PIN; + unsigned int _pin_tx = PZEM004T_TX_PIN; + IPAddress _ip; + HardwareSerial * _serial = NULL; + PZEM004T * _pzem = NULL; + +}; + +#endif // SENSOR_SUPPORT && PZEM004T_SUPPORT diff --git a/code/espurna/sensors/SHT3XI2CSensor.h b/code/espurna/sensors/SHT3XI2CSensor.h index 95e149fe..21234097 100644 --- a/code/espurna/sensors/SHT3XI2CSensor.h +++ b/code/espurna/sensors/SHT3XI2CSensor.h @@ -1,19 +1,18 @@ // ----------------------------------------------------------------------------- // SHT3X Sensor over I2C (Wemos) -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && SHT3X_I2C_SUPPORT #pragma once +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + + #include "Arduino.h" #include "I2CSensor.h" -#if I2C_USE_BRZO -#include -#else -#include -#endif class SHT3XI2CSensor : public I2CSensor { @@ -36,13 +35,15 @@ class SHT3XI2CSensor : public I2CSensor { void begin() { if (!_dirty) return; - _dirty = false; // I2C auto-discover unsigned char addresses[] = {0x45}; _address = _begin_i2c(_address, sizeof(addresses), addresses); if (_address == 0) return; + _ready = true; + _dirty = false; + } // Descriptive name of the sensor @@ -54,49 +55,20 @@ class SHT3XI2CSensor : public I2CSensor { // Type for slot # index unsigned char type(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - if (index == 0) return MAGNITUDE_TEMPERATURE; - if (index == 1) return MAGNITUDE_HUMIDITY; - } - _error = SENSOR_ERROR_OUT_OF_RANGE; + if (index == 0) return MAGNITUDE_TEMPERATURE; + if (index == 1) return MAGNITUDE_HUMIDITY; return MAGNITUDE_NONE; } // Pre-read hook (usually to populate registers with up-to-date data) void pre() { - unsigned char buffer[6]; + _error = SENSOR_ERROR_OK; - #if I2C_USE_BRZO - buffer[0] = 0x2C; - buffer[1] = 0x06; - brzo_i2c_start_transaction(_address, I2C_SCL_FREQUENCY); - brzo_i2c_write(buffer, 2, false); - #else - Wire.beginTransmission(_address); - Wire.write(0x2C); - Wire.write(0x06); - if (Wire.endTransmission() != 0) { - _error = SENSOR_ERROR_TIMEOUT; - return; - } - #endif - - delay(500); - - #if I2C_USE_BRZO - brzo_i2c_read(buffer, 6, false); - brzo_i2c_end_transaction(); - #else - Wire.requestFrom(_address, (unsigned char) 6); - for (int i=0; i<6; i++) buffer[i] = Wire.read(); - delay(50); - if (Wire.available() != 0) { - _error = SENSOR_ERROR_CRC; - return; - } - #endif + unsigned char buffer[6]; + i2c_write_uint8(_address, 0x2C, 0x06); + nice_delay(500); + i2c_read_buffer(_address, buffer, 6); // cTemp msb, cTemp lsb, cTemp crc, humidity msb, humidity lsb, humidity crc _temperature = ((((buffer[0] * 256.0) + buffer[1]) * 175) / 65535.0) - 45; @@ -106,10 +78,8 @@ class SHT3XI2CSensor : public I2CSensor { // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return _temperature; if (index == 1) return _humidity; - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } diff --git a/code/espurna/sensors/SI7021Sensor.h b/code/espurna/sensors/SI7021Sensor.h index 6dbfb457..9e778aaa 100644 --- a/code/espurna/sensors/SI7021Sensor.h +++ b/code/espurna/sensors/SI7021Sensor.h @@ -1,19 +1,19 @@ // ----------------------------------------------------------------------------- // SI7021 / HTU21D Sensor over I2C -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && SI7021_SUPPORT #pragma once +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + + + #include "Arduino.h" #include "I2CSensor.h" -#if I2C_USE_BRZO -#include -#else -#include -#endif #define SI7021_SCL_FREQUENCY 200 @@ -25,6 +25,9 @@ #define SI7021_CMD_TMP_NOHOLD 0xF3 #define SI7021_CMD_HUM_NOHOLD 0xF5 +PROGMEM const char si7021_chip_si7021_name[] = "SI7021"; +PROGMEM const char si7021_chip_htu21d_name[] = "HTU21D"; + class SI7021Sensor : public I2CSensor { public: @@ -43,76 +46,61 @@ class SI7021Sensor : public I2CSensor { // Initialization method, must be idempotent void begin() { - if (!_dirty) return; - _dirty = false; - - // I2C auto-discover - unsigned char addresses[] = {0x40}; - _address = _begin_i2c(_address, sizeof(addresses), addresses); - if (_address == 0) return; - - // Check device - #if I2C_USE_BRZO - uint8_t buffer[2] = {0xFC, 0xC9}; - brzo_i2c_start_transaction(_address, SI7021_SCL_FREQUENCY); - brzo_i2c_write(buffer, 2, false); - brzo_i2c_read(buffer, 1, false); - brzo_i2c_end_transaction(); - _chip = buffer[0]; - #else - Wire.beginTransmission(_address); - Wire.write(0xFC); - Wire.write(0xC9); - Wire.endTransmission(); - Wire.requestFrom(_address, (unsigned char) 1); - _chip = Wire.read(); - #endif - - if ((_chip != SI7021_CHIP_SI7021) & (_chip != SI7021_CHIP_HTU21D)) { - i2cReleaseLock(_address); - _error = SENSOR_ERROR_UNKNOWN_ID; - } else { - _count = 2; - } - + _init(); + _dirty = !_ready; } // Descriptive name of the sensor String description() { + char name[10]; + strncpy_P(name, + _chip == SI7021_CHIP_SI7021 ? + si7021_chip_si7021_name : + si7021_chip_htu21d_name, + sizeof(name) + ); char buffer[25]; - snprintf(buffer, sizeof(buffer), "%s @ I2C (0x%02X)", chipAsString().c_str(), _address); + snprintf(buffer, sizeof(buffer), "%s @ I2C (0x%02X)", name, _address); return String(buffer); } + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + // Type for slot # index unsigned char type(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - if (index == 0) return MAGNITUDE_TEMPERATURE; - if (index == 1) return MAGNITUDE_HUMIDITY; - } - _error = SENSOR_ERROR_OUT_OF_RANGE; + if (index == 0) return MAGNITUDE_TEMPERATURE; + if (index == 1) return MAGNITUDE_HUMIDITY; return MAGNITUDE_NONE; } + // Pre-read hook (usually to populate registers with up-to-date data) + void pre() { + + _error = SENSOR_ERROR_UNKNOWN_ID; + if (_chip == 0) return; + _error = SENSOR_ERROR_OK; + + double value; + + value = _read(SI7021_CMD_TMP_NOHOLD); + if (_error != SENSOR_ERROR_OK) return; + _temperature = (175.72 * value / 65536) - 46.85; + + value = _read(SI7021_CMD_HUM_NOHOLD); + if (_error != SENSOR_ERROR_OK) return; + value = (125.0 * value / 65536) - 6; + _humidity = constrain(value, 0, 100); + + } + // Current value for slot # index double value(unsigned char index) { - if (index < _count) { - _error = SENSOR_ERROR_OK; - double value; - if (index == 0) { - value = read(SI7021_CMD_TMP_NOHOLD); - value = (175.72 * value / 65536) - 46.85; - } - if (index == 1) { - value = read(SI7021_CMD_HUM_NOHOLD); - value = (125.0 * value / 65536) - 6; - value = constrain(value, 0, 100); - } - return value; - } - _error = SENSOR_ERROR_OUT_OF_RANGE; + if (index == 0) return _temperature; + if (index == 1) return _humidity; return 0; } @@ -122,59 +110,63 @@ class SI7021Sensor : public I2CSensor { // Protected // --------------------------------------------------------------------- - unsigned int read(uint8_t command) { + void _init() { + + // I2C auto-discover + unsigned char addresses[] = {0x40}; + _address = _begin_i2c(_address, sizeof(addresses), addresses); + if (_address == 0) return; + + // Check device + i2c_write_uint8(_address, 0xFC, 0xC9); + _chip = i2c_read_uint8(_address); - unsigned char bytes = (command == 0xE0) ? 2 : 3; + if ((_chip != SI7021_CHIP_SI7021) & (_chip != SI7021_CHIP_HTU21D)) { + + _count = 0; + i2cReleaseLock(_address); + _previous_address = 0; + _error = SENSOR_ERROR_UNKNOWN_ID; - #if I2C_USE_BRZO - uint8_t buffer[2] = {command, 0x00}; - brzo_i2c_start_transaction(_address, SI7021_SCL_FREQUENCY); - brzo_i2c_write(buffer, 1, false); - #else - Wire.beginTransmission(_address); - Wire.write(command); - Wire.endTransmission(); - #endif + // Setting _address to 0 forces auto-discover + // This might be necessary at this stage if there is a + // different sensor in the hardcoded address + _address = 0; + + } else { + _count = 2; + } + + _ready = true; + + } + + unsigned int _read(uint8_t command) { + + // Request measurement + i2c_write_uint8(_address, command); // When not using clock stretching (*_NOHOLD commands) delay here // is needed to wait for the measurement. // According to datasheet the max. conversion time is ~22ms unsigned long start = millis(); - while (millis() - start < 50) delay(1); - - #if I2C_USE_BRZO - brzo_i2c_read(buffer, 2, false); - brzo_i2c_end_transaction(); - unsigned int msb = buffer[0]; - unsigned int lsb = buffer[1]; - #else - Wire.requestFrom(_address, bytes); - if (Wire.available() != bytes) { - _error = SENSOR_ERROR_CRC; - return 0; - } - unsigned int msb = Wire.read(); - unsigned int lsb = Wire.read(); - #endif + nice_delay(50); // Clear the last to bits of LSB to 00. // According to datasheet LSB of RH is always xxxxxx10 - lsb &= 0xFC; - - unsigned int value = (msb << 8) | lsb; + unsigned int value = i2c_read_uint16(_address) & 0xFFFC; + // We should be checking there are no pending bytes in the buffer + // and raise a CRC error if there are _error = SENSOR_ERROR_OK; - return value; - } + return value; - String chipAsString() { - if (_chip == SI7021_CHIP_SI7021) return String("SI7021"); - if (_chip == SI7021_CHIP_HTU21D) return String("HTU21D"); - return String("Unknown"); } unsigned char _chip; + double _temperature = 0; + double _humidity = 0; }; diff --git a/code/espurna/sensors/SenseAirSensor.h b/code/espurna/sensors/SenseAirSensor.h new file mode 100644 index 00000000..c73d25e3 --- /dev/null +++ b/code/espurna/sensors/SenseAirSensor.h @@ -0,0 +1,233 @@ +// ----------------------------------------------------------------------------- +// SenseAir S8 CO2 Sensor +// Uses SoftwareSerial library +// Contribution by Yonsm Guo +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && SENSEAIR_SUPPORT + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" + +#include + +// SenseAir sensor utils +class SenseAir +{ +protected: + SoftwareSerial *_serial; // Should initialized by child class + +public: + int sendCommand(byte command[]) { + byte recv_buf[7] = {0xff}; + byte data_buf[2] = {0xff}; + long value = -1; + + _serial->write(command, 8); //Send the byte array + delay(50); + + // Read answer from sensor + int ByteCounter = 0; + while(_serial->available()) { + recv_buf[ByteCounter] = _serial->read(); + ByteCounter++; + } + + data_buf[0] = recv_buf[3]; + data_buf[1] = recv_buf[4]; + value = (data_buf[0] << 8) | (data_buf[1]); + + return value; + } + + int readCo2(void) { + int co2 = 0; + byte frame[8] = {0}; + buildFrame(0xFE, 0x04, 0x03, 1, frame); + co2 = sendCommand(frame); + return co2; + } + +private: + // Compute the MODBUS RTU CRC + static unsigned int modRTU_CRC(byte buf[], int len, byte checkSum[2]) { + unsigned int crc = 0xFFFF; + + for (int pos = 0; pos < len; pos++) { + crc ^= (unsigned int)buf[pos]; // XOR byte into least sig. byte of crc + + for (int i = 8; i != 0; i--) { // Loop over each bit + if ((crc & 0x0001) != 0) { // If the LSB is set + crc >>= 1; // Shift right and XOR 0xA001 + crc ^= 0xA001; + } + else // Else LSB is not set + crc >>= 1; // Just shift right + } + } + // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes) + checkSum[1] = (byte)((crc >> 8) & 0xFF); + checkSum[0] = (byte)(crc & 0xFF); + return crc; + } + + static int getBitOfInt(int reg, int pos) { + // Create a mask + int mask = 0x01 << pos; + + // Mask the status register + int masked_register = mask & reg; + + // Shift the result of masked register back to position 0 + int result = masked_register >> pos; + + return result; + } + + + static void buildFrame(byte slaveAddress, + byte functionCode, + short startAddress, + short numberOfRegisters, + byte frame[8]) { + frame[0] = slaveAddress; + frame[1] = functionCode; + frame[2] = (byte)(startAddress >> 8); + frame[3] = (byte)(startAddress); + frame[4] = (byte)(numberOfRegisters >> 8); + frame[5] = (byte)(numberOfRegisters); + // CRC-calculation + byte checkSum[2] = {0}; + modRTU_CRC(frame, 6, checkSum); + frame[6] = checkSum[0]; + frame[7] = checkSum[1]; + } +}; + +// +class SenseAirSensor : public BaseSensor, SenseAir { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + SenseAirSensor(): BaseSensor() { + _count = 1; + _co2 = 0; + _lastCo2 = 0; + _serial = NULL; + _sensor_id = SENSOR_SENSEAIR_ID; + } + + ~SenseAirSensor() { + if (_serial) delete _serial; + _serial = NULL; + } + + void setRX(unsigned char pin_rx) { + if (_pin_rx == pin_rx) return; + _pin_rx = pin_rx; + _dirty = true; + } + + void setTX(unsigned char pin_tx) { + if (_pin_tx == pin_tx) return; + _pin_tx = pin_tx; + _dirty = true; + } + + // --------------------------------------------------------------------- + + unsigned char getRX() { + return _pin_rx; + } + + unsigned char getTX() { + return _pin_tx; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + + if (!_dirty) return; + + if (_serial) delete _serial; + + _serial = new SoftwareSerial(_pin_rx, _pin_tx, false, 64); + _serial->enableIntTx(false); + _serial->begin(9600); + _serial->enableRx(true); + + _startTime = 0; + _ready = true; + _dirty = false; + } + + // Descriptive name of the sensor + String description() { + char buffer[28]; + snprintf(buffer, sizeof(buffer), "SenseAir S8 @ SwSerial(%u,%u)", _pin_rx, _pin_tx); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + } + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[6]; + snprintf(buffer, sizeof(buffer), "%u:%u", _pin_rx, _pin_tx); + return String(buffer); + } + + // Type for slot # index + unsigned char type(unsigned char index) { + return MAGNITUDE_CO2; + } + + void pre() { + + if (millis() - _startTime < 20000) { + _error = SENSOR_ERROR_WARM_UP; + return; + } + + _error = SENSOR_ERROR_OK; + + unsigned int co2 = readCo2(); + if (co2 >= 5000 || co2 < 100) + { + _co2 = _lastCo2; + } + else + { + _co2 = (co2 > _lastCo2 + 2000) ? _lastCo2 : co2; + _lastCo2 = co2; + } + } + + // Current value for slot # index + double value(unsigned char index) { + return _co2; + } + + protected: + unsigned int _pin_rx; + unsigned int _pin_tx; + unsigned long _startTime; + unsigned int _co2; + unsigned int _lastCo2; +}; + + +#endif // SENSOR_SUPPORT && SENSEAIR_SUPPORT diff --git a/code/espurna/sensors/TMP3XSensor.h b/code/espurna/sensors/TMP3XSensor.h new file mode 100644 index 00000000..6052797e --- /dev/null +++ b/code/espurna/sensors/TMP3XSensor.h @@ -0,0 +1,94 @@ +// ----------------------------------------------------------------------------- +// TMP3X Temperature Analog Sensor +// Copyright (C) 2018 by Xose Pérez +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && TMP3X_SUPPORT + +#pragma once + +// Set ADC to TOUT pin +#undef ADC_MODE_VALUE +#define ADC_MODE_VALUE ADC_TOUT + +#include "Arduino.h" +#include "BaseSensor.h" + +#define TMP3X_TMP35 35 +#define TMP3X_TMP36 36 +#define TMP3X_TMP37 37 + +class TMP3XSensor : public BaseSensor { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + TMP3XSensor(): BaseSensor() { + _count = 1; + _sensor_id = SENSOR_TMP3X_ID; + } + + void setType(unsigned char type) { + if (35 <= type && type <= 37) { + _type = type; + } + } + + unsigned char getType() { + return _type; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + pinMode(0, INPUT); + _ready = true; + } + + // Descriptive name of the sensor + String description() { + char buffer[14]; + snprintf(buffer, sizeof(buffer), "TMP%d @ TOUT", _type); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String("0"); + } + + // Type for slot # index + unsigned char type(unsigned char index) { + if (index == 0) return MAGNITUDE_TEMPERATURE; + return MAGNITUDE_NONE; + } + + // Current value for slot # index + double value(unsigned char index) { + if (index == 0) { + double mV = 3300.0 * analogRead(0) / 1024.0; + if (_type == TMP3X_TMP35) return mV / 10.0; + if (_type == TMP3X_TMP36) return mV / 10.0 - 50.0; + if (_type == TMP3X_TMP37) return mV / 20.0; + } + return 0; + } + + private: + + unsigned char _type = TMP3X_TMP35; + +}; + +#endif // SENSOR_SUPPORT && TMP3X_SUPPORT diff --git a/code/espurna/sensors/V9261FSensor.h b/code/espurna/sensors/V9261FSensor.h index 4ffdeb20..67068c17 100644 --- a/code/espurna/sensors/V9261FSensor.h +++ b/code/espurna/sensors/V9261FSensor.h @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- // V9261F based power monitor -// Copyright (C) 2017 by Xose Pérez +// Copyright (C) 2017-2018 by Xose Pérez // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && V9261F_SUPPORT @@ -9,6 +9,9 @@ #include "Arduino.h" #include "BaseSensor.h" +extern "C" { + #include "libs/fs_math.h" +} #include @@ -20,7 +23,7 @@ class V9261FSensor : public BaseSensor { // Public // --------------------------------------------------------------------- - V9261FSensor(): BaseSensor() { + V9261FSensor(): BaseSensor(), _data() { _count = 6; _sensor_id = SENSOR_V9261F_ID; } @@ -61,22 +64,35 @@ class V9261FSensor : public BaseSensor { void begin() { if (!_dirty) return; - _dirty = false; if (_serial) delete _serial; - _serial = new SoftwareSerial(_pin_rx, SW_SERIAL_UNUSED_PIN, _inverted, 256); + _serial = new SoftwareSerial(_pin_rx, SW_SERIAL_UNUSED_PIN, _inverted, 32); + _serial->enableIntTx(false); _serial->begin(V9261F_BAUDRATE); + _ready = true; + _dirty = false; + } // Descriptive name of the sensor String description() { char buffer[28]; - snprintf(buffer, sizeof(buffer), "V9261F @ SwSerial(%i,NULL)", _pin_rx); + snprintf(buffer, sizeof(buffer), "V9261F @ SwSerial(%u,NULL)", _pin_rx); return String(buffer); } + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + return String(_pin_rx); + } + // Loop-like method, call it in your main loop void tick() { _read(); @@ -84,27 +100,23 @@ class V9261FSensor : public BaseSensor { // Type for slot # index unsigned char type(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_CURRENT; if (index == 1) return MAGNITUDE_VOLTAGE; if (index == 2) return MAGNITUDE_POWER_ACTIVE; if (index == 3) return MAGNITUDE_POWER_REACTIVE; if (index == 4) return MAGNITUDE_POWER_APPARENT; if (index == 5) return MAGNITUDE_POWER_FACTOR; - _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } // Current value for slot # index double value(unsigned char index) { - _error = SENSOR_ERROR_OK; if (index == 0) return _current; if (index == 1) return _voltage; if (index == 2) return _active; if (index == 3) return _reactive; if (index == 4) return _apparent; if (index == 5) return _apparent > 0 ? 100 * _active / _apparent : 100; - _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; } @@ -194,7 +206,7 @@ class V9261FSensor : public BaseSensor { if (_voltage < 0) _voltage = 0; if (_current < 0) _current = 0; - _apparent = sqrt(_reactive * _reactive + _active * _active); + _apparent = fs_sqrt(_reactive * _reactive + _active * _active); } diff --git a/code/espurna/settings.ino b/code/espurna/settings.ino index b8b0f90f..b05f9a08 100644 --- a/code/espurna/settings.ino +++ b/code/espurna/settings.ino @@ -2,87 +2,71 @@ SETTINGS MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ -#include -#include "spi_flash.h" +#include +#include #include "libs/EmbedisWrap.h" -#include - -#if TELNET_SUPPORT - #include "libs/StreamInjector.h" - #ifdef DEBUG_PORT - StreamInjector _serial = StreamInjector(DEBUG_PORT); - #else - StreamInjector _serial = StreamInjector(Serial); - #endif - EmbedisWrap embedis(_serial); -#else - #ifdef DEBUG_PORT - EmbedisWrap embedis(DEBUG_PORT); - #else - EmbedisWrap embedis(_serial); - #endif -#endif +#include +#include "libs/StreamInjector.h" + +StreamInjector _serial = StreamInjector(TERMINAL_BUFFER_SIZE); +EmbedisWrap embedis(_serial, TERMINAL_BUFFER_SIZE); + +#if TERMINAL_SUPPORT +#if SERIAL_RX_ENABLED + char _serial_rx_buffer[TERMINAL_BUFFER_SIZE]; + static unsigned char _serial_rx_pointer = 0; +#endif // SERIAL_RX_ENABLED +#endif // TERMINAL_SUPPORT bool _settings_save = false; // ----------------------------------------------------------------------------- -// Settings +// Reverse engineering EEPROM storage format // ----------------------------------------------------------------------------- -#if TELNET_SUPPORT - void settingsInject(void *data, size_t len) { - _serial.inject((char *) data, len); - } -#endif - -size_t settingsMaxSize() { - size_t size = EEPROM_SIZE; - if (size > SPI_FLASH_SEC_SIZE) size = SPI_FLASH_SEC_SIZE; - size = (size + 3) & (~3); - return size; -} - unsigned long settingsSize() { unsigned pos = SPI_FLASH_SEC_SIZE - 1; - while (size_t len = EEPROM.read(pos)) { + while (size_t len = EEPROMr.read(pos)) { pos = pos - len - 2; } return SPI_FLASH_SEC_SIZE - pos; } -unsigned int settingsKeyCount() { +// ----------------------------------------------------------------------------- + +unsigned int _settingsKeyCount() { unsigned count = 0; unsigned pos = SPI_FLASH_SEC_SIZE - 1; - while (size_t len = EEPROM.read(pos)) { + while (size_t len = EEPROMr.read(pos)) { pos = pos - len - 2; - len = EEPROM.read(pos); + len = EEPROMr.read(pos); pos = pos - len - 2; count ++; } return count; } -String settingsKeyName(unsigned int index) { +String _settingsKeyName(unsigned int index) { String s; unsigned count = 0; unsigned pos = SPI_FLASH_SEC_SIZE - 1; - while (size_t len = EEPROM.read(pos)) { + while (size_t len = EEPROMr.read(pos)) { pos = pos - len - 2; if (count == index) { s.reserve(len); for (unsigned char i = 0 ; i < len; i++) { - s += (char) EEPROM.read(pos + i + 1); + s += (char) EEPROMr.read(pos + i + 1); } break; } count++; - len = EEPROM.read(pos); + len = EEPROMr.read(pos); pos = pos - len - 2; } @@ -90,287 +74,230 @@ String settingsKeyName(unsigned int index) { } -bool settingsRestore(JsonObject& data) { +std::vector _settingsKeys() { - const char* app = data["app"]; - if (strcmp(app, APP_NAME) != 0) return false; + // Get sorted list of keys + std::vector keys; - for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) { - EEPROM.write(i, 0xFF); - } + //unsigned int size = settingsKeyCount(); + unsigned int size = _settingsKeyCount(); + for (unsigned int i=0; i()); - } + //String key = settingsKeyName(i); + String key = _settingsKeyName(i); + bool inserted = false; + for (unsigned char j=0; j 0) { + keys.insert(keys.begin() + j, key); + inserted = true; + break; + } - DEBUG_MSG_P(PSTR("[SETTINGS] Settings restored successfully\n")); - return true; + } -} + // If we could not insert it, just push it at the end + if (!inserted) keys.push_back(key); -void settingsFactoryReset() { - for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) { - EEPROM.write(i, 0xFF); } - EEPROM.commit(); + + return keys; } -void settingsHelp() { - unsigned char len = embedis.getCommandsCount(); - DEBUG_MSG_P(PSTR("\nAvailable commands:\n\n")); - for (unsigned char i=0; i commands; + unsigned char size = embedis.getCommandCount(); + for (unsigned int i=0; i 0) { + commands.insert(commands.begin() + j, command); + inserted = true; + break; + } + } + + // If we could not insert it, just push it at the end + if (!inserted) commands.push_back(command); + } - DEBUG_MSG_P(PSTR("\n")); -} -void settingsSetup() { + // Output the list + DEBUG_MSG_P(PSTR("Available commands:\n")); + for (unsigned char i=0; i %s\n"), (commands[i]).c_str()); + } - EEPROM.begin(SPI_FLASH_SEC_SIZE); +} - #if TELNET_SUPPORT - _serial.callback([](uint8_t ch) { - telnetWrite(ch); - }); - #endif +void _settingsKeysCommand() { - Embedis::dictionary( F("EEPROM"), - SPI_FLASH_SEC_SIZE, - [](size_t pos) -> char { return EEPROM.read(pos); }, - [](size_t pos, char value) { EEPROM.write(pos, value); }, - #if SETTINGS_AUTOSAVE - []() { _settings_save = true; } - #else - []() {} - #endif - ); + // Get sorted list of keys + std::vector keys = _settingsKeys(); - Embedis::hardware( F("WIFI"), [](Embedis* e) { - StreamString s; - WiFi.printDiag(s); - DEBUG_MSG(s.c_str()); - }, 0); + // Write key-values + DEBUG_MSG_P(PSTR("Current settings:\n")); + for (unsigned int i=0; i %s => \"%s\"\n"), (keys[i]).c_str(), value.c_str()); + } - // ------------------------------------------------------------------------- + unsigned long freeEEPROM = SPI_FLASH_SEC_SIZE - settingsSize(); + DEBUG_MSG_P(PSTR("Number of keys: %d\n"), keys.size()); + DEBUG_MSG_P(PSTR("Current EEPROM sector: %u\n"), EEPROMr.current()); + DEBUG_MSG_P(PSTR("Free EEPROM: %d bytes (%d%%)\n"), freeEEPROM, 100 * freeEEPROM / SPI_FLASH_SEC_SIZE); - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - Embedis::command( F("BRIGHTNESS"), [](Embedis* e) { - if (e->argc > 1) { - lightBrightness(String(e->argv[1]).toInt()); - lightUpdate(true, true); - } - DEBUG_MSG_P(PSTR("Brightness: %d\n"), lightBrightness()); - DEBUG_MSG_P(PSTR("+OK\n")); - }); - #endif +} - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - Embedis::command( F("CHANNEL"), [](Embedis* e) { - if (e->argc < 2) { - DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); - } - int id = String(e->argv[1]).toInt(); - if (e->argc > 2) { - int value = String(e->argv[2]).toInt(); - lightChannel(id, value); - lightUpdate(true, true); - } - DEBUG_MSG_P(PSTR("Channel #%d: %d\n"), id, lightChannel(id)); - DEBUG_MSG_P(PSTR("+OK\n")); - }); - #endif +void _settingsFactoryResetCommand() { + for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) { + EEPROMr.write(i, 0xFF); + } + EEPROMr.commit(); +} - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - Embedis::command( F("COLOR"), [](Embedis* e) { - if (e->argc > 1) { - String color = String(e->argv[1]); - lightColor(color.c_str()); - lightUpdate(true, true); - } - DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); - DEBUG_MSG_P(PSTR("+OK\n")); - }); - #endif +void _settingsInitCommands() { #if DEBUG_SUPPORT - Embedis::command( F("CRASH"), [](Embedis* e) { + settingsRegisterCommand(F("CRASH"), [](Embedis* e) { debugDumpCrashInfo(); + debugClearCrashInfo(); DEBUG_MSG_P(PSTR("+OK\n")); }); #endif - Embedis::command( F("DUMP"), [](Embedis* e) { - unsigned int size = settingsKeyCount(); - for (unsigned int i=0; i %s\n"), key.c_str(), value.c_str()); - } - DEBUG_MSG_P(PSTR("+OK\n")); - }); - - Embedis::command( F("DUMP.RAW"), [](Embedis* e) { - bool ascii = false; - if (e->argc == 2) ascii = String(e->argv[1]).toInt() == 1; - for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) { - if (i % 16 == 0) DEBUG_MSG_P(PSTR("\n[%04X] "), i); - byte c = EEPROM.read(i); - if (ascii && 32 <= c && c <= 126) { - DEBUG_MSG_P(PSTR(" %c "), c); - } else { - DEBUG_MSG_P(PSTR("%02X "), c); - } - } - DEBUG_MSG_P(PSTR("\n+OK\n")); - }); - - Embedis::command( F("EEPROM"), [](Embedis* e) { - unsigned long freeEEPROM = SPI_FLASH_SEC_SIZE - settingsSize(); - DEBUG_MSG_P(PSTR("Number of keys: %d\n"), settingsKeyCount()); - DEBUG_MSG_P(PSTR("Free EEPROM: %d bytes (%d%%)\n"), freeEEPROM, 100 * freeEEPROM / SPI_FLASH_SEC_SIZE); + settingsRegisterCommand(F("COMMANDS"), [](Embedis* e) { + _settingsHelpCommand(); DEBUG_MSG_P(PSTR("+OK\n")); }); - Embedis::command( F("ERASE.CONFIG"), [](Embedis* e) { + settingsRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) { DEBUG_MSG_P(PSTR("+OK\n")); resetReason(CUSTOM_RESET_TERMINAL); ESP.eraseConfig(); *((int*) 0) = 0; // see https://github.com/esp8266/Arduino/issues/1494 }); - Embedis::command( F("FACTORY.RESET"), [](Embedis* e) { - settingsFactoryReset(); + #if I2C_SUPPORT + + settingsRegisterCommand(F("I2C.SCAN"), [](Embedis* e) { + i2cScan(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + + settingsRegisterCommand(F("I2C.CLEAR"), [](Embedis* e) { + i2cClearBus(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + + #endif + + settingsRegisterCommand(F("FACTORY.RESET"), [](Embedis* e) { + _settingsFactoryResetCommand(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + + settingsRegisterCommand(F("GPIO"), [](Embedis* e) { + if (e->argc < 2) { + DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); + return; + } + int pin = String(e->argv[1]).toInt(); + //if (!gpioValid(pin)) { + // DEBUG_MSG_P(PSTR("-ERROR: Invalid GPIO\n")); + // return; + //} + if (e->argc > 2) { + bool state = String(e->argv[2]).toInt() == 1; + digitalWrite(pin, state); + } + DEBUG_MSG_P(PSTR("GPIO %d is %s\n"), pin, digitalRead(pin) == HIGH ? "HIGH" : "LOW"); DEBUG_MSG_P(PSTR("+OK\n")); }); - Embedis::command( F("HEAP"), [](Embedis* e) { + settingsRegisterCommand(F("HEAP"), [](Embedis* e) { DEBUG_MSG_P(PSTR("Free HEAP: %d bytes\n"), getFreeHeap()); DEBUG_MSG_P(PSTR("+OK\n")); }); - Embedis::command( F("HELP"), [](Embedis* e) { - settingsHelp(); + settingsRegisterCommand(F("HELP"), [](Embedis* e) { + _settingsHelpCommand(); DEBUG_MSG_P(PSTR("+OK\n")); }); - Embedis::command( F("INFO"), [](Embedis* e) { - welcome(); - wifiStatus(); + settingsRegisterCommand(F("INFO"), [](Embedis* e) { + info(); + wifiDebug(); + //StreamString s; + //WiFi.printDiag(s); + //DEBUG_MSG(s.c_str()); DEBUG_MSG_P(PSTR("+OK\n")); }); - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - Embedis::command( F("KELVIN"), [](Embedis* e) { - if (e->argc > 1) { - String color = String("K") + String(e->argv[1]); - lightColor(color.c_str()); - lightUpdate(true, true); - } - DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); - DEBUG_MSG_P(PSTR("+OK\n")); - }); - #endif - - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - Embedis::command( F("MIRED"), [](Embedis* e) { - if (e->argc > 1) { - String color = String("M") + String(e->argv[1]); - lightColor(color.c_str()); - lightUpdate(true, true); - } - DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); - DEBUG_MSG_P(PSTR("+OK\n")); - }); - #endif - - #if NOFUSS_SUPPORT - Embedis::command( F("NOFUSS"), [](Embedis* e) { - DEBUG_MSG_P(PSTR("+OK\n")); - nofussRun(); - }); - #endif + settingsRegisterCommand(F("KEYS"), [](Embedis* e) { + _settingsKeysCommand(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); - Embedis::command( F("RELAY"), [](Embedis* e) { + settingsRegisterCommand(F("GET"), [](Embedis* e) { if (e->argc < 2) { DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); + return; } - int id = String(e->argv[1]).toInt(); - if (e->argc > 2) { - int value = String(e->argv[2]).toInt(); - if (value == 2) { - relayToggle(id); - } else { - relayStatus(id, value == 1); + + for (unsigned char i = 1; i < e->argc; i++) { + String key = String(e->argv[i]); + String value; + if (!Embedis::get(key, value)) { + DEBUG_MSG_P(PSTR("> %s =>\n"), key.c_str()); + continue; } + + DEBUG_MSG_P(PSTR("> %s => \"%s\"\n"), key.c_str(), value.c_str()); } - DEBUG_MSG_P(PSTR("Status: %s\n"), relayStatus(id) ? "true" : "false"); - DEBUG_MSG_P(PSTR("+OK\n")); - }); - Embedis::command( F("RESET"), [](Embedis* e) { DEBUG_MSG_P(PSTR("+OK\n")); - deferredReset(100, CUSTOM_RESET_TERMINAL); }); - #if MQTT_SUPPORT - Embedis::command( F("RESET.MQTT"), [](Embedis* e) { - mqttConfigure(); - mqttDisconnect(); + #if WEB_SUPPORT + settingsRegisterCommand(F("RELOAD"), [](Embedis* e) { + wsReload(); DEBUG_MSG_P(PSTR("+OK\n")); }); #endif + + settingsRegisterCommand(F("RESET"), [](Embedis* e) { + DEBUG_MSG_P(PSTR("+OK\n")); + deferredReset(100, CUSTOM_RESET_TERMINAL); + }); - Embedis::command( F("RESET.WIFI"), [](Embedis* e) { - wifiConfigure(); - wifiDisconnect(); + settingsRegisterCommand(F("RESET.SAFE"), [](Embedis* e) { + EEPROMr.write(EEPROM_CRASH_COUNTER, SYSTEM_CHECK_MAX); DEBUG_MSG_P(PSTR("+OK\n")); + deferredReset(100, CUSTOM_RESET_TERMINAL); }); - Embedis::command( F("UPTIME"), [](Embedis* e) { + settingsRegisterCommand(F("UPTIME"), [](Embedis* e) { DEBUG_MSG_P(PSTR("Uptime: %d seconds\n"), getUptime()); DEBUG_MSG_P(PSTR("+OK\n")); }); - - DEBUG_MSG_P(PSTR("[SETTINGS] EEPROM size: %d bytes\n"), SPI_FLASH_SEC_SIZE); - DEBUG_MSG_P(PSTR("[SETTINGS] Settings size: %d bytes\n"), settingsSize()); - -} - -void settingsDump() { - unsigned int size = settingsKeyCount(); - for (unsigned int i=0; i %s\n"), key.c_str(), value.c_str()); - } -} - -void settingsLoop() { - if (_settings_save) { - //DEBUG_MSG_P(PSTR("[SETTINGS] Saving\n")); - EEPROM.commit(); - _settings_save = false; - } - #if TERMINAL_SUPPORT - embedis.process(); - #endif -} - -void saveSettings() { - #if not SETTINGS_AUTOSAVE - _settings_save = true; - #endif - //settingsDump(); } +// ----------------------------------------------------------------------------- +// Key-value API // ----------------------------------------------------------------------------- void moveSetting(const char * from, const char * to) { @@ -416,3 +343,147 @@ bool hasSetting(const String& key) { bool hasSetting(const String& key, unsigned int index) { return getSetting(key, index, "").length() != 0; } + +void saveSettings() { + #if not SETTINGS_AUTOSAVE + _settings_save = true; + #endif +} + +void resetSettings() { + _settingsFactoryResetCommand(); +} + +// ----------------------------------------------------------------------------- +// Settings +// ----------------------------------------------------------------------------- + +void settingsInject(void *data, size_t len) { + _serial.inject((char *) data, len); +} + +Stream & settingsSerial() { + return (Stream &) _serial; +} + +size_t settingsMaxSize() { + size_t size = EEPROM_SIZE; + if (size > SPI_FLASH_SEC_SIZE) size = SPI_FLASH_SEC_SIZE; + size = (size + 3) & (~3); + return size; +} + +bool settingsRestoreJson(JsonObject& data) { + + const char* app = data["app"]; + if (strcmp(app, APP_NAME) != 0) return false; + + for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) { + EEPROMr.write(i, 0xFF); + } + + for (auto element : data) { + if (strcmp(element.key, "app") == 0) continue; + if (strcmp(element.key, "version") == 0) continue; + setSetting(element.key, element.value.as()); + } + + saveSettings(); + + DEBUG_MSG_P(PSTR("[SETTINGS] Settings restored successfully\n")); + return true; + +} + +void settingsGetJson(JsonObject& root) { + + // Get sorted list of keys + std::vector keys = _settingsKeys(); + + // Add the key-values to the json object + for (unsigned int i=0; i char { return EEPROMr.read(pos); }, + [](size_t pos, char value) { EEPROMr.write(pos, value); }, + #if SETTINGS_AUTOSAVE + []() { _settings_save = true; } + #else + []() {} + #endif + ); + + _settingsInitCommands(); + + #if TERMINAL_SUPPORT + #if SERIAL_RX_ENABLED + SERIAL_RX_PORT.begin(SERIAL_RX_BAUDRATE); + #endif // SERIAL_RX_ENABLED + #endif // TERMINAL_SUPPORT + + // Register loop + espurnaRegisterLoop(settingsLoop); + +} + +void settingsLoop() { + + if (_settings_save) { + EEPROMr.commit(); + _settings_save = false; + } + + + #if TERMINAL_SUPPORT + + #if DEBUG_SERIAL_SUPPORT + while (DEBUG_PORT.available()) { + _serial.inject(DEBUG_PORT.read()); + } + #endif + + embedis.process(); + + #if SERIAL_RX_ENABLED + + while (SERIAL_RX_PORT.available() > 0) { + char rc = Serial.read(); + _serial_rx_buffer[_serial_rx_pointer++] = rc; + if ((_serial_rx_pointer == TERMINAL_BUFFER_SIZE) || (rc == 10)) { + settingsInject(_serial_rx_buffer, (size_t) _serial_rx_pointer); + _serial_rx_pointer = 0; + } + } + + #endif // SERIAL_RX_ENABLED + + #endif // TERMINAL_SUPPORT + +} diff --git a/code/espurna/ssdp.ino b/code/espurna/ssdp.ino index 9b4ca697..6ecf0f58 100644 --- a/code/espurna/ssdp.ino +++ b/code/espurna/ssdp.ino @@ -2,7 +2,7 @@ SSDP MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez Uses SSDP library by PawelDino (https://github.com/PawelDino) https://github.com/esp8266/Arduino/issues/2283#issuecomment-299635604 @@ -10,31 +10,74 @@ https://github.com/esp8266/Arduino/issues/2283#issuecomment-299635604 #if SSDP_SUPPORT -#include +#include + +const char _ssdp_template[] PROGMEM = + "" + "" + "" + "1" + "0" + "" + "http://%s:%u/" + "" + "%s" + "%s" + "/" + "%u" + "%s" + "%s" + "%s" + "%s" + "%s" + "uuid:38323636-4558-4dda-9188-cda0e6%06x" + "" + "\r\n" + "\r\n"; void ssdpSetup() { - SSDPDevice.setName(getSetting("hostname")); - SSDPDevice.setDeviceType("urn:schemas-upnp-org:device:BinaryLight:1"); - SSDPDevice.setSchemaURL("description.xml"); - SSDPDevice.setSerialNumber(ESP.getChipId()); - SSDPDevice.setURL("/"); - SSDPDevice.setModelName(DEVICE); - SSDPDevice.setModelNumber(""); - SSDPDevice.setManufacturer(MANUFACTURER); - - #if WEB_SUPPORT - webServer()->on("/description.xml", HTTP_GET, [](AsyncWebServerRequest *request) { - DEBUG_MSG_P(PSTR("[SSDP] Schema request\n")); - String schema = SSDPDevice.schema(); - request->send(200, "application/xml", schema.c_str()); - }); - #endif + webServer()->on("/description.xml", HTTP_GET, [](AsyncWebServerRequest *request) { -} + DEBUG_MSG_P(PSTR("[SSDP] Schema request\n")); + + IPAddress ip = WiFi.localIP(); + uint32_t chipId = ESP.getChipId(); + + char response[strlen_P(_ssdp_template) + 100]; + snprintf_P(response, sizeof(response), _ssdp_template, + WiFi.localIP().toString().c_str(), // ip + webPort(), // port + SSDP_DEVICE_TYPE, // device type + getSetting("hostname").c_str(), // friendlyName + chipId, // serialNumber + APP_NAME, // modelName + APP_VERSION, // modelNumber + APP_WEBSITE, // modelURL + DEVICE_NAME, // manufacturer + "", // manufacturerURL + chipId // UUID + ); + + request->send(200, "text/xml", response); + + }); + + SSDP.setSchemaURL("description.xml"); + SSDP.setHTTPPort(webPort()); + SSDP.setDeviceType(SSDP_DEVICE_TYPE); //https://github.com/esp8266/Arduino/issues/2283 + SSDP.setName(getSetting("hostname")); + SSDP.setSerialNumber(String(ESP.getChipId())); + SSDP.setModelName(APP_NAME); + SSDP.setModelNumber(APP_VERSION); + SSDP.setModelURL(APP_WEBSITE); + SSDP.setManufacturer(DEVICE_NAME); + SSDP.setManufacturerURL(""); + SSDP.setURL("/"); + SSDP.begin(); + + DEBUG_MSG_P(PSTR("[SSDP] Started\n")); -void ssdpLoop() { - SSDPDevice.handleClient(); } #endif // SSDP_SUPPORT diff --git a/code/espurna/static/index.html.gz.h b/code/espurna/static/index.html.gz.h index f4d24cb1..554aed3e 100644 --- a/code/espurna/static/index.html.gz.h +++ b/code/espurna/static/index.html.gz.h @@ -1,3076 +1,3253 @@ -#define index_html_gz_len 61446 +#define index_html_gz_len 64998 const uint8_t index_html_gz[] PROGMEM = { -0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xec,0xbd,0x79,0x7f,0xda,0xcc,0x92,0x30,0xfa,0xff, -0x7c,0x0a,0x99,0x9c,0xf1,0xc0,0xb1,0xd8,0x8d,0x8d,0x71,0x48,0x06,0xef,0x24,0x5e,0xc1,0x4b,0x9c,0x8c, -0xe7,0xf9,0x09,0xd4,0x80,0x6c,0x21,0x61,0x49,0x18,0x93,0xc4,0xf7,0xfb,0xdc,0xcf,0x71,0xbf,0xd8,0xad, -0xea,0x45,0x6a,0x6d,0xd8,0x4e,0x9c,0x39,0xcf,0xfb,0xfe,0xe6,0xc9,0x39,0x09,0x6a,0xf5,0x52,0x5d,0x55, -0x5d,0x5b,0x57,0xb7,0xde,0x2f,0xed,0x9c,0x6c,0x9f,0x5f,0x9f,0xee,0x2a,0x23,0x6f,0x6c,0x7e,0x78,0xcf, -0xff,0x26,0x9a,0xfe,0xe1,0xbd,0x67,0x78,0x26,0xf9,0xb0,0xdb,0x3d,0x9d,0x3a,0x96,0xa6,0x94,0x0a,0xf0, -0xe7,0x7d,0x91,0x15,0xbe,0x1f,0x13,0x4f,0x53,0xfa,0x23,0xcd,0x71,0x89,0xd7,0xcc,0x4c,0xbd,0x41,0xbe, -0x9e,0xf9,0xf0,0xde,0x34,0xac,0x3b,0xc5,0x21,0x66,0x33,0xe3,0x8e,0x6c,0xc7,0xeb,0x4f,0x3d,0xc5,0xe8, -0xdb,0x56,0x46,0x19,0x39,0x64,0xd0,0xcc,0xe8,0x9a,0xa7,0x35,0x8c,0xb1,0x36,0x24,0xc5,0x89,0x35,0xdc, -0xec,0x69,0x2e,0x59,0x5b,0x55,0x5b,0xad,0xd6,0x56,0xab,0xb5,0xdb,0xda,0x85,0xbf,0xf1,0xdf,0x76,0x6b, -0xcb,0xc6,0x9f,0x7b,0x43,0xf8,0x6b,0x1b,0xff,0x6a,0x9d,0xe1,0x5f,0xed,0x96,0x78,0x2f,0xfe,0x83,0xe2, -0xad,0xf6,0x21,0xfc,0xe8,0x6e,0xcf,0x5a,0xff,0xfb,0xdf,0xdf,0xec,0xbf,0x22,0xfc,0xd7,0x3a,0x85,0xbf, -0x66,0x3b,0xf0,0x57,0x9d,0x3d,0x47,0xff,0x3b,0xee,0x5d,0x95,0xad,0xab,0x99,0xb3,0xbe,0xb7,0x71,0xff, -0xd9,0x98,0x90,0xb5,0xb9,0xeb,0x7c,0x99,0x7b,0xce,0xe7,0xda,0x86,0xf3,0x79,0x3e,0x1d,0xac,0x55,0x5c, -0xc7,0xde,0x87,0xe7,0xb5,0x6d,0x47,0x9b,0x4f,0x47,0x87,0xdb,0x0f,0xee,0xf5,0x40,0xaf,0xea,0x65,0x8d, -0xf6,0xf7,0x80,0xfd,0x47,0x3b,0xdd,0x39,0x2f,0x79,0x27,0x2d,0xb3,0xa6,0x5d,0xcf,0xaf,0x8e,0x8d,0xaf, -0x83,0x61,0xf1,0xf4,0xee,0xb0,0x78,0x74,0xde,0x2a,0x15,0xbf,0xef,0xce,0x8e,0x8a,0xf5,0xf9,0xd1,0xf9, -0x97,0xe2,0xd1,0xed,0x6e,0x99,0x3d,0x6f,0xec,0x75,0x76,0x6f,0x8b,0xde,0x3a,0x59,0x1d,0x6e,0xcf,0x9c, -0x43,0x0e,0x6f,0xf2,0x7c,0xd6,0x57,0x8a,0xa3,0x9d,0xb3,0xd2,0xf1,0xde,0xa7,0x71,0x6d,0xaa,0x8f,0x2b, -0xa6,0xad,0x6d,0xd4,0xeb,0x27,0xdf,0x8b,0x1b,0x6d,0x63,0xd7,0x2c,0x3e,0xd6,0x49,0xfb,0xa1,0xae,0x1f, -0x6c,0xef,0x14,0xcf,0xee,0x3e,0xed,0x15,0x9d,0xb5,0x8d,0x87,0xd5,0x87,0xda,0xca,0xe0,0x8e,0xa4,0xc3, -0x1b,0xc5,0xd7,0x69,0x79,0x63,0x70,0x3d,0x9a,0xae,0x4f,0xeb,0xb7,0x77,0x9f,0xb6,0x3a,0x83,0x55,0xda, -0xdf,0xc1,0xe3,0xaa,0x51,0x9c,0xb7,0x47,0x9f,0x06,0x75,0x98,0xcf,0x41,0xbd,0xb7,0xef,0x4d,0xab,0x9f, -0x56,0x88,0xfd,0xa9,0x77,0x51,0x3e,0xbe,0xdc,0xc5,0xf6,0x3b,0x9e,0xa3,0x55,0x86,0x31,0x7c,0xd0,0xf9, -0x1c,0x9f,0x9f,0xad,0xb6,0x0e,0x49,0x75,0x7a,0x50,0xdb,0x3d,0x2b,0xf5,0x8a,0x87,0xf3,0xd5,0xc7,0xe2, -0xf7,0xd6,0x03,0xe0,0x63,0x76,0xf8,0xfd,0x14,0x9f,0xe7,0xfc,0x99,0xe2,0xeb,0xba,0x72,0x6c,0x6e,0xd4, -0x8c,0x2f,0xe3,0xfe,0x97,0xf3,0xd2,0x46,0x67,0x3d,0x1d,0xde,0xc3,0x7e,0xf5,0xf8,0x91,0x20,0x7d,0x6e, -0xef,0xc7,0x93,0x7b,0xfb,0x7e,0x72,0xaf,0x4d,0xdb,0xf7,0xda,0xd8,0x19,0xe1,0xf3,0x6a,0xf7,0x1e,0x9e, -0x77,0xee,0x35,0xe3,0x7e,0xa8,0x5d,0xdd,0x4d,0x90,0x9e,0xda,0xda,0x76,0x59,0xff,0x72,0x45,0xa2,0xb0, -0x46,0xf9,0xe5,0x34,0x1d,0x5f,0xff,0xfb,0xdf,0xff,0xec,0x7f,0x74,0x4d,0x9c,0xe2,0x1a,0xde,0xa1,0x34, -0xe1,0xcf,0xa7,0xf8,0x6e,0x07,0x69,0xb4,0x45,0xd7,0xcc,0x01,0x3c,0x0d,0x51,0x34,0xaf,0xe0,0x13,0x7b, -0xfb,0x5d,0xaa,0x1f,0x6e,0xdf,0x6a,0x36,0x33,0x5c,0x9b,0x58,0xda,0x98,0x34,0x33,0x0f,0x06,0x99,0x4d, -0x40,0x77,0x64,0x14,0x50,0x1c,0x1e,0xb1,0x40,0xbb,0xcc,0x0c,0xdd,0x1b,0x35,0x75,0xf2,0x60,0xf4,0x49, -0x9e,0x3e,0xa8,0x86,0x65,0x78,0x86,0x66,0xe6,0xdd,0xbe,0x66,0x92,0x66,0x19,0xba,0x70,0xbd,0x39,0xe8, -0xa5,0xe2,0x3f,0x97,0xfe,0x0d,0xd4,0x15,0x51,0x1e,0xca,0xa8,0xae,0xfe,0x6d,0xdb,0x9e,0xcc,0x1d,0x63, -0x38,0xf2,0x94,0x4a,0xa9,0x5c,0x55,0xae,0xb5,0x91,0x6d,0x2f,0xfd,0xdb,0x21,0x74,0x64,0xb9,0x44,0x57, -0xa6,0x96,0x4e,0x1c,0xc5,0x1b,0x11,0x65,0xab,0xbb,0xa3,0xf0,0xe2,0xc2,0xbf,0x8d,0x3c,0x6f,0xe2,0x36, -0x8a,0xc5,0xa1,0xe1,0x8d,0xa6,0xbd,0x42,0xdf,0x1e,0x17,0xe7,0xd8,0xb2,0x38,0x81,0xae,0x8b,0x3d,0xd3, -0xee,0x15,0xc7,0x9a,0xeb,0x11,0xa7,0x78,0xd8,0xde,0xde,0x3d,0xee,0xee,0x16,0xc6,0xfa,0xbf,0xfd,0xb3, -0x88,0x83,0x5b,0xb6,0x33,0xd6,0x4c,0xe3,0x3b,0x29,0xf4,0x5d,0x57,0x79,0xf8,0xef,0x6a,0xa1,0xa4,0xfc, -0x54,0x8e,0xda,0xe7,0xa2,0x77,0x78,0x82,0x6e,0x0b,0x86,0x5d,0xf4,0xab,0x4a,0x50,0x66,0xfb,0x39,0xe5, -0x18,0x54,0xa6,0xa9,0xb9,0xca,0xbe,0x66,0x9a,0xda,0x70,0x04,0x00,0x6a,0x96,0xae,0x7c,0xb2,0x2d,0xcd, -0x1b,0x69,0x96,0x72,0x4c,0x34,0x93,0x0d,0xa6,0x44,0x06,0x83,0xb1,0x0a,0xd5,0xa4,0xd1,0xc4,0x24,0x2c, -0x42,0x7b,0x2e,0x86,0xdb,0xfd,0xb3,0x58,0xc0,0x79,0xe5,0x7b,0x53,0xcf,0xb3,0xad,0xc6,0xc0,0xee,0x4f, -0x5d,0x55,0x6b,0x68,0x7d,0xcf,0x78,0x20,0xf0,0x63,0x64,0x3f,0x10,0xe7,0x87,0x3d,0xf5,0x40,0xbb,0x93, -0x46,0xe9,0x89,0xd5,0xf6,0xb4,0x9e,0x49,0x54,0xfa,0xf7,0x8f,0x9e,0xed,0x00,0x1e,0xf3,0xd0,0xb9,0xa9, -0x4d,0x5c,0xd2,0x10,0x3f,0x36,0xf9,0x0b,0x77,0xa2,0xf5,0x0d,0x6b,0x08,0x6d,0xd1,0xbc,0xf8,0x31,0x00, -0xc2,0xe6,0x07,0xda,0xd8,0x30,0xe7,0x0d,0x57,0xb3,0xdc,0xbc,0x4b,0x1c,0x63,0xb0,0x99,0x1f,0xbb,0x79, -0x8f,0x3c,0x7a,0x79,0x17,0x20,0xcb,0x6b,0xfa,0xed,0xd4,0xf5,0x1a,0xe5,0x52,0xe9,0xdf,0x37,0xf3,0x33, -0xd2,0xbb,0x33,0xbc,0xe4,0xb7,0x4f,0x3d,0x5b,0x9f,0xff,0x18,0x6b,0xce,0xd0,0xb0,0x60,0x04,0xcd,0xf1, -0x8c,0x3e,0x40,0xa6,0xb9,0x86,0x4e,0x54,0x1d,0x18,0xcb,0x30,0x5d,0x75,0x60,0x0c,0xfb,0xda,0xc4,0x33, -0x6c,0x0b,0x7f,0x02,0xfc,0xea,0xc0,0xb6,0x81,0x80,0x2a,0x5a,0x3a,0xf8,0xcf,0xd0,0xb1,0xa7,0x13,0x75, -0xac,0x19,0x96,0x3a,0x26,0xd6,0x54,0xb5,0xb4,0x07,0xd5,0x25,0x7d,0xda,0xc2,0x9d,0x8e,0xa1,0xfb,0xf9, -0x0f,0xdd,0x70,0x27,0xa6,0x36,0x6f,0x00,0x03,0xf4,0xef,0x9e,0xb4,0xa9,0x6e,0xd8,0x6a,0x5f,0xb3,0x1e, -0x34,0x57,0x9d,0x38,0xf6,0xd0,0x21,0xae,0xab,0x3e,0xc0,0xa8,0xb6,0x5f,0xd3,0xb0,0x10,0x67,0x79,0xda, -0x60,0x13,0xb0,0x08,0xa0,0x01,0xd3,0x02,0xea,0x87,0x56,0x03,0xad,0x1f,0x7c,0xcb,0x3a,0x6a,0x58,0xb6, -0x97,0xfd,0x86,0x2c,0xef,0xd8,0xa6,0x7b,0x93,0xf3,0xbb,0xb0,0x6c,0x8b,0x6c,0x8e,0x08,0x72,0x07,0xcc, -0xee,0xdb,0xc8,0xd0,0x75,0x62,0xdd,0xa8,0x1e,0x19,0xc3,0x6b,0x8f,0x84,0xea,0x3d,0x69,0x3f,0x7a,0x5a, -0xff,0x0e,0xe7,0x62,0xe9,0x48,0x0e,0xdb,0x69,0x80,0xa8,0xb5,0x00,0xff,0x0e,0xac,0xa4,0x27,0xad,0xd7, -0x73,0xbe,0x51,0x03,0xee,0x46,0xd0,0xac,0x67,0x03,0xd1,0xc7,0x8d,0xf2,0xe4,0x51,0xd1,0xe1,0x27,0xd1, -0x9f,0x7a,0xaa,0x3d,0xf1,0x18,0x3a,0x5c,0x00,0xc6,0x1a,0x32,0x7a,0xcd,0x18,0x08,0xeb,0xa5,0xd2,0x93, -0x3e,0xb0,0x58,0x19,0x5d,0x73,0x0d,0xc3,0x83,0x09,0xf5,0x9f,0x46,0x65,0x5e,0x08,0xf4,0x69,0x54,0xc8, -0x78,0x93,0x93,0xa4,0xb0,0xb6,0x4e,0xc6,0x4a,0xe9,0x09,0x1e,0xef,0x24,0xf0,0x1a,0xef,0x06,0x83,0xd2, -0x26,0x83,0xf1,0x5d,0x09,0x7a,0x75,0x81,0x25,0x4d,0xa9,0x8b,0x3a,0x90,0xd6,0x9d,0xf6,0x00,0xfb,0x13, -0xa9,0x74,0xbd,0xf6,0xef,0x9b,0x14,0xa7,0x02,0x25,0x9b,0x13,0xdb,0x35,0x90,0x4c,0x0d,0xb0,0x3b,0x35, -0x64,0xd9,0x54,0x44,0x63,0x4f,0x9e,0x3d,0x69,0xe4,0x0b,0x35,0x32,0xc6,0xbe,0x7f,0xf0,0xd9,0xe7,0x0b, -0x15,0x2c,0x31,0xc6,0x43,0x8e,0x16,0xc0,0xb4,0xfb,0x30,0xa4,0x34,0x69,0x38,0xc0,0x28,0xb9,0x1f,0xb8, -0x06,0x06,0xa6,0x3d,0x6b,0x30,0x02,0x3c,0x31,0x2e,0x12,0x6c,0x57,0x86,0x19,0xae,0x96,0x26,0x8f,0x4f, -0x23,0x07,0x7a,0x78,0x44,0x50,0x91,0xdf,0xb9,0x04,0x03,0x24,0x3f,0x06,0x24,0x9c,0x00,0xf3,0x21,0x23, -0x03,0x49,0xb4,0xa0,0x5b,0x6d,0xea,0xd9,0x4f,0x7d,0x1b,0x58,0xf6,0xae,0xa7,0xab,0x58,0xc7,0xd5,0xc6, -0x93,0xd0,0x52,0x19,0xdb,0x96,0x8d,0x2b,0x89,0xa8,0xfe,0xaf,0xcd,0x00,0x31,0x00,0xc2,0x13,0x5b,0xc1, -0x20,0x1c,0x27,0x53,0x4f,0xa2,0x22,0x31,0x81,0x91,0x83,0x31,0x19,0xce,0x0d,0x0b,0x24,0x8b,0xe1,0xd1, -0x1e,0xfc,0x07,0x7f,0x15,0xc9,0x12,0x81,0xf5,0xf7,0x43,0xc6,0x3a,0x13,0x20,0x7c,0xbc,0x60,0x12,0x0f, -0x86,0x6b,0x80,0x3c,0x10,0x70,0xb0,0x81,0x7f,0xd0,0x55,0x4b,0xd9,0x70,0x00,0xcd,0x18,0xa3,0xf2,0x1a, -0x28,0x0e,0x14,0xda,0xfd,0x37,0x6f,0x3e,0x21,0x4d,0x56,0x7c,0xa3,0x4a,0x45,0xb0,0xaa,0x88,0x17,0x2a, -0x01,0xc2,0x8d,0x0d,0xef,0xe6,0x87,0x90,0x0a,0xda,0x64,0x42,0x34,0xe8,0xbe,0x4f,0x1a,0xac,0xfd,0x66, -0x7f,0xea,0xb8,0x30,0xc5,0x89,0x6d,0x00,0xfe,0x1d,0x3e,0xd8,0x37,0x58,0x29,0x28,0xad,0xf4,0x1b,0x79, -0x58,0xbf,0xf0,0x07,0x6f,0xa4,0x93,0x81,0x36,0x35,0x3d,0xde,0xa8,0xd1,0xc8,0x8f,0xed,0xef,0x79,0x2a, -0x13,0xf3,0x86,0x65,0x81,0xa8,0xa0,0xed,0xe2,0xe5,0x3e,0xe7,0x6c,0x4e,0x34,0x5d,0x67,0xd2,0x4e,0x02, -0xba,0x3f,0x22,0xfd,0x3b,0xe0,0x83,0xf0,0xdc,0x34,0x58,0xf9,0x37,0x32,0xc7,0xf8,0xab,0xf2,0x31,0xb9, -0x1b,0x6b,0x3a,0xee,0x11,0xe7,0x06,0x86,0xe7,0x93,0xa7,0x63,0x83,0x80,0x35,0xac,0x10,0xb5,0x52,0x6a, -0x83,0x10,0x0f,0xd7,0xfe,0xc1,0x09,0x4a,0xd9,0x4f,0xc6,0x31,0x60,0xb4,0x3f,0x4a,0xc4,0x31,0x92,0x73, -0x60,0x10,0x53,0xdf,0x4c,0xe6,0xf4,0x30,0xef,0xb0,0x07,0x24,0x3c,0x43,0x38,0x93,0x73,0x38,0xc6,0x4d, -0x8e,0xbf,0x44,0x79,0x9b,0x8c,0x83,0x04,0x88,0x82,0xb9,0xb0,0x82,0x7c,0x1f,0x81,0x32,0x13,0x26,0x9f, -0xd6,0x40,0x07,0x25,0xe8,0x68,0x28,0x31,0x92,0x66,0x47,0xb9,0x93,0x4e,0x0f,0xd8,0x4e,0xd0,0x14,0xa5, -0xa3,0x6b,0x9b,0x86,0xae,0xb8,0x86,0x09,0xcc,0xee,0xaf,0x13,0xa5,0x32,0x09,0x08,0x55,0xa8,0x82,0x10, -0x51,0x0a,0x6b,0x15,0xfa,0xcf,0x3a,0x4a,0x14,0x93,0x0c,0x89,0xa5,0xab,0x1e,0xfc,0x6f,0xf4,0x23,0x20, -0x28,0x2b,0x0e,0x64,0x4d,0x81,0x09,0x15,0x55,0x48,0xf7,0x90,0x50,0x5f,0x32,0xc6,0x68,0x0f,0x69,0x20, -0xbf,0x19,0xbe,0x50,0x4c,0x8d,0xb5,0x47,0x66,0x09,0x31,0x05,0x29,0x51,0x71,0x33,0xac,0xa5,0x58,0x93, -0xe1,0x0f,0x93,0x78,0x9e,0xa4,0x89,0xf3,0x85,0x2a,0x08,0x8c,0x4d,0xba,0x34,0x41,0x35,0x00,0x18,0x58, -0x0a,0x22,0xc3,0x18,0x83,0x30,0x71,0x27,0x84,0xe8,0x9b,0xb2,0xec,0xd9,0x73,0x08,0xe9,0xc2,0x0a,0x56, -0x5b,0x8e,0x31,0xb6,0xd5,0xcc,0x8e,0x63,0x03,0x36,0xb0,0x24,0xa3,0x1e,0x10,0xc0,0x09,0x0a,0x5c,0x7c, -0xa9,0x99,0xaa,0xa4,0xd2,0x05,0x2c,0x02,0xd1,0xc8,0xd7,0xd1,0xb2,0x81,0x49,0xa4,0x42,0xb0,0x01,0xb0, -0x40,0xae,0x48,0x2b,0xc8,0xb5,0xf3,0x54,0xd8,0x38,0xf6,0x4c,0x99,0x39,0xda,0x64,0x53,0xb4,0x89,0x14, -0x27,0xd5,0x14,0xf4,0x46,0xbd,0x90,0xe7,0x3c,0x4b,0xfb,0x07,0x55,0x06,0x86,0x43,0xd0,0x15,0x15,0x76, -0x80,0xab,0xbb,0x06,0x7b,0x91,0xd6,0xe2,0xe9,0x3f,0xc7,0x44,0x37,0x34,0x05,0x54,0x17,0xb5,0xd2,0xb2, -0xd8,0xc3,0x08,0x88,0x41,0xeb,0x3a,0x60,0x24,0x52,0x1a,0xe6,0xd4,0x84,0x17,0xcc,0xc0,0xca,0xfd,0xa0, -0x36,0x94,0x22,0x08,0x15,0x26,0xdf,0x53,0xc1,0x9e,0x80,0x63,0x95,0xb7,0x2d,0x73,0xae,0x34,0xf2,0x76, -0x1e,0x34,0x03,0x33,0xd0,0x44,0xfd,0x19,0x30,0x91,0x44,0xd6,0xd5,0x2a,0xb0,0x1d,0x7b,0x37,0xe5,0x75, -0xa6,0xf9,0x72,0xf0,0x2b,0xfc,0xbb,0x22,0x3d,0x84,0x7e,0xaf,0x4a,0x0f,0x55,0xe9,0xb7,0x5c,0x5e,0x93, -0x7e,0xaf,0x49,0xbf,0xeb,0xc1,0xef,0x52,0xa8,0xa7,0xf0,0x80,0xe1,0x51,0x2a,0xa1,0xa7,0x6a,0xe8,0x69, -0x35,0xf4,0x54,0x0b,0x3d,0xad,0x85,0x9e,0xd6,0x43,0x4f,0xf5,0xd0,0xd3,0x86,0xfc,0x54,0x09,0x3f,0x54, -0xa5,0xdf,0xc1,0xb4,0x2a,0x21,0xf0,0x2b,0x21,0x80,0x2b,0xe1,0x1e,0x42,0x00,0x57,0x42,0x00,0x57,0xc3, -0x0f,0xf2,0xef,0x9a,0xf4,0x3b,0xc0,0x5a,0xa8,0xf5,0xaa,0x54,0xa9,0x26,0xe3,0x2f,0x84,0x86,0x5a,0xa8, -0xd6,0x9a,0xf4,0x3b,0xe8,0x36,0x84,0xa9,0x75,0xb9,0xab,0xf5,0xf0,0x9b,0xa0,0x49,0x08,0x81,0x88,0xbf, -0xa8,0x18,0x61,0x76,0xc0,0x66,0x88,0x07,0x79,0x59,0xc4,0x08,0x03,0xbb,0x2b,0x2a,0x6d,0x42,0xd2,0x2a, -0x64,0x29,0x7f,0xb7,0xd1,0x24,0x15,0xb2,0x4b,0xf9,0xd6,0x07,0xa7,0xc5,0xfd,0x67,0x93,0x01,0x72,0x93, -0xe2,0x3f,0x3c,0xf9,0x94,0x46,0x40,0x99,0x70,0x5c,0x2d,0x94,0xd7,0xd6,0xd6,0xff,0x5d,0x7a,0x25,0x4d, -0xbb,0x12,0xd4,0xab,0x17,0xaa,0xf0,0x9f,0x5c,0xaf,0x1e,0xa2,0x1f,0xaf,0x56,0xae,0x14,0x6a,0x72,0xa5, -0xb5,0x10,0xcd,0x44,0xa5,0xb5,0xc2,0x5a,0x64,0xd0,0x1a,0x7f,0x55,0x29,0x05,0xa5,0xb5,0xa0,0x45,0xa5, -0x54,0xa8,0x47,0x86,0x5f,0x0d,0x91,0x4d,0xd4,0x93,0x06,0x5f,0x97,0x8a,0x37,0x62,0xb3,0xac,0x86,0x48, -0xc8,0xeb,0x55,0xab,0x91,0x59,0xca,0x4c,0xb7,0x21,0xd5,0x5b,0x97,0x67,0x59,0xf1,0xa1,0x5f,0x95,0xa0, -0x0f,0xaf,0x6c,0x64,0x4c,0x51,0xa9,0x1c,0x9d,0xbd,0x4c,0x8e,0x5a,0x6c,0xa2,0x92,0x40,0x90,0xe8,0x51, -0x93,0x87,0x92,0x08,0x50,0x8b,0x11,0x74,0x35,0xca,0xd5,0xa2,0x66,0x94,0xa4,0x55,0x7f,0x1e,0x6b,0x72, -0xe7,0x91,0x65,0x54,0x17,0x75,0xc2,0x94,0x5e,0x8b,0x88,0x0b,0x51,0x2b,0x46,0x6a,0x89,0x2c,0xeb,0x31, -0xaa,0xd6,0x23,0x92,0x40,0x54,0x94,0x47,0x92,0xe8,0xb0,0x1e,0xa5,0xeb,0xaa,0x3f,0x85,0xba,0x34,0x85, -0x4a,0x84,0x14,0x6b,0xa2,0x4e,0x94,0xdc,0x61,0x01,0xb6,0xee,0xcf,0xb5,0x1e,0xa2,0x77,0x58,0x4a,0x57, -0x24,0xa2,0x6c,0x44,0x49,0x5b,0x91,0x28,0xb3,0x11,0x23,0x6d,0xa2,0xce,0x09,0x8b,0xc6,0x9a,0x3f,0x21, -0xea,0xc8,0xcb,0x86,0x63,0xb2,0x0b,0xcd,0x04,0xc3,0xe6,0x6c,0x64,0x78,0x84,0x0a,0x1c,0x34,0xd8,0xa8, -0x6a,0x8f,0x88,0x9b,0x31,0x18,0x52,0x26,0x61,0x12,0x87,0x95,0xf4,0x09,0xfa,0x02,0x11,0xd7,0xc0,0xb7, -0x08,0xa6,0x20,0x42,0xf2,0xba,0xa3,0x0d,0x99,0xbf,0x1d,0x2a,0x66,0x6e,0x0c,0x7f,0x81,0x56,0x7f,0x42, -0xa9,0x1b,0x2f,0x8c,0x16,0x84,0xa6,0x97,0xe0,0x3f,0xf8,0xe6,0xe1,0x66,0x60,0x17,0x4a,0x2d,0xf2,0xd4, -0x99,0xfb,0x05,0x3b,0xee,0x39,0x13,0x22,0xd4,0x7d,0xba,0x35,0xc1,0xc9,0x22,0xcb,0x5e,0xd9,0x85,0xe4, -0x4e,0x28,0x1a,0xa3,0xbe,0x3d,0x8c,0x76,0x30,0x42,0xc7,0x9d,0xfc,0xd5,0xd5,0x55,0xfe,0xd3,0x19,0xf6, -0xb4,0x6c,0x49,0xc5,0x3f,0x85,0x7a,0x6e,0x33,0x66,0x65,0xbf,0xdb,0xd8,0xd8,0x10,0xa5,0x52,0xfc,0x62, -0x33,0x16,0xdc,0x78,0x47,0xd6,0xf0,0x0f,0x9b,0x7f,0x60,0xd8,0x33,0x02,0x70,0x3f,0x02,0x9d,0xac,0xa9, -0xdb,0x00,0x4b,0x3d,0x8c,0x4f,0x1a,0xd6,0x0a,0xe1,0xa0,0x11,0x47,0x0b,0x0f,0x7e,0x49,0x03,0xd3,0xed, -0x2b,0xdf,0x78,0x45,0xde,0xd4,0x1c,0x40,0x1e,0x0c,0x02,0x10,0x66,0x25,0x68,0x55,0x79,0x96,0xa5,0x5a, -0x4e,0x01,0xf9,0x19,0x2a,0x2b,0xe7,0x72,0x9b,0xb1,0x8e,0x7f,0xb3,0xc3,0xf0,0x14,0x79,0x08,0x2f,0x34, -0x21,0x56,0xc6,0xfc,0xad,0x91,0xa6,0x83,0x79,0x5c,0x52,0xf0,0x0f,0x62,0x3f,0xd4,0x19,0x0c,0x60,0x58, -0xe0,0x04,0xa9,0xf8,0x76,0x2d,0xf2,0xb6,0xc2,0x5f,0x86,0xc7,0x13,0xce,0xb4,0x9a,0x58,0xda,0x48,0x00, -0x27,0x78,0x99,0xc0,0x92,0xfe,0xbb,0x38,0xa9,0x24,0xbf,0x9d,0xf3,0x09,0x23,0x79,0x14,0x9d,0xb4,0xd4, -0x46,0x7e,0xf6,0xe6,0x8d,0xc2,0xaa,0x58,0xfe,0xe0,0x84,0x82,0x58,0x00,0xdf,0x80,0x70,0x2f,0x96,0x61, -0x82,0xd6,0xe6,0xa2,0x21,0x4f,0x1e,0x00,0xe7,0x6e,0x7c,0xe9,0xe6,0x99,0x93,0x16,0x0e,0xbc,0x85,0x2a, -0x4c,0xc0,0x47,0xd2,0x9c,0x79,0x78,0x32,0x4c,0x12,0x00,0x6e,0xb4,0xc4,0xba,0x5a,0x62,0xe5,0x78,0x38, -0xef,0x5d,0xa9,0xb4,0x5e,0x27,0xeb,0x62,0x4d,0x0d,0x06,0x83,0x04,0x29,0xa1,0x84,0x96,0xec,0x9b,0xdb, -0x6c,0xc2,0xfb,0x8d,0xac,0xb0,0xe0,0x99,0x3a,0xa3,0xd2,0x72,0x2e,0x97,0xcb,0x69,0xef,0xc2,0x4c,0xf5, -0xdc,0x5c,0x1a,0x03,0xc3,0x71,0xbd,0x7c,0x7f,0x64,0x98,0xc2,0x7d,0xce,0x03,0x94,0x79,0x93,0x0c,0x3c, -0x69,0xa1,0x6f,0x86,0x82,0x9b,0xd1,0xb7,0xcf,0x0e,0x02,0xd6,0x66,0xc2,0x18,0x14,0xf2,0xf4,0x41,0xd2, -0x5e,0x3b,0x3c,0x60,0xe6,0x33,0x49,0x10,0x0b,0xe1,0x91,0x21,0xa4,0xe4,0x4d,0x2c,0x50,0xc2,0x5e,0xea, -0x9a,0x47,0x16,0xbd,0x03,0x39,0x4f,0xf2,0xa0,0x1a,0x35,0xf3,0xb9,0x5a,0x69,0xef,0xc9,0x58,0x33,0x52, -0x1b,0x8f,0x41,0xb2,0x8f,0xd2,0x5e,0xf2,0xe8,0x52,0xca,0xdb,0x09,0x98,0xec,0xc8,0x63,0x69,0xef,0x79, -0x78,0x26,0xe5,0xad,0x47,0x52,0x61,0x42,0x8e,0x4c,0x7d,0xb7,0x60,0xa2,0x53,0x27,0xb5,0xcb,0x19,0x21, -0x77,0xa1,0x77,0x3c,0x64,0x2a,0x95,0xf8,0xd1,0xd3,0x90,0x76,0x2b,0xac,0x81,0x7a,0x4b,0xb4,0x54,0xe2, -0x3a,0xad,0xdf,0xef,0xcb,0xb2,0x86,0x8a,0x4f,0x2e,0x77,0xab,0xf0,0xff,0x77,0xba,0xae,0x47,0x16,0xd4, -0x2a,0x70,0x51,0xb2,0x5d,0x93,0x1c,0x2d,0x8b,0x4e,0x4e,0x8e,0xb5,0xfd,0x0f,0xc3,0xbd,0x90,0xd7,0x03, -0x58,0x2a,0x08,0x4b,0xcd,0xb7,0x31,0x92,0x41,0x0f,0xa9,0x86,0xe4,0x1e,0x17,0x56,0xa1,0x6b,0xe8,0xd9, -0x1a,0xd2,0x4a,0x7a,0x51,0xdd,0xc5,0xb5,0xd8,0xaa,0x5a,0x58,0x85,0xad,0xad,0x85,0x55,0x44,0xfc,0x76, -0x51,0x1d,0x7f,0x9d,0x2d,0xac,0x25,0x82,0xa1,0x8b,0xea,0xe0,0x9a,0x7b,0xa6,0x02,0xac,0xbc,0xc5,0x35, -0x9e,0x45,0x0c,0xae,0xc2,0x85,0x15,0xe8,0x5a,0x8c,0xd7,0xe0,0x86,0x74,0xac,0x5c,0xac,0x4b,0xf6,0x26, -0xd8,0xa5,0xdc,0x0c,0xf6,0x24,0x51,0x4f,0x96,0x2b,0x1b,0x03,0xa2,0xa5,0x71,0xa5,0x88,0xcd,0x2f,0x04, -0x6c,0x60,0x98,0xcf,0xcc,0x8d,0x85,0xf3,0x23,0x90,0xf0,0xa1,0x15,0xd4,0x9c,0xb8,0x68,0x64,0x18,0xd8, -0x4f,0x31,0xbc,0x1a,0x7b,0x43,0x3b,0x14,0x7b,0x4c,0x74,0xe1,0x96,0x12,0xc3,0xbb,0xc9,0xeb,0x46,0xda, -0xf0,0x58,0xb4,0x76,0x9e,0xad,0x46,0xd7,0xcf,0x8b,0x6a,0x49,0x6b,0xe8,0xc5,0xf5,0x9f,0xaf,0xc9,0xd6, -0xd2,0xb3,0xd5,0xd8,0x7a,0x7a,0xb6,0x1a,0x5f,0x53,0xcf,0xd6,0xf3,0xd7,0xd5,0xb3,0x35,0xf9,0xda,0x7a, -0xb6,0x1e,0xae,0xaf,0x17,0x54,0x82,0x35,0xf6,0x7c,0xad,0x17,0x21,0x0e,0xd7,0xda,0xb3,0x95,0xe8,0x7a, -0x4b,0xae,0xc5,0xd6,0x5c,0xf2,0x3b,0xb1,0xee,0xe2,0x1b,0x68,0x21,0xdb,0x3a,0xee,0xb0,0x69,0x44,0x87, -0x17,0xfc,0xa9,0xaf,0xe9,0x15,0xbd,0x1a,0x5f,0x96,0xd0,0xb1,0x8e,0xfe,0x6a,0x12,0x38,0x89,0xef,0x7c, -0x70,0xfc,0xb7,0x09,0xa6,0x33,0x21,0x44,0x0c,0xbc,0xbe,0xbe,0x1e,0x91,0x10,0xa0,0xe6,0xe2,0xab,0x89, -0x2e,0x65,0x50,0x79,0x0f,0xa0,0x7d,0xf5,0x34,0x71,0x94,0xf4,0x3e,0x2c,0x96,0x44,0x0d,0xbe,0xf5,0xfa, -0xae,0xb7,0xb1,0xaa,0xad,0xd6,0x23,0x00,0x90,0x8d,0x6a,0xa5,0xa2,0xbf,0x4c,0x44,0x89,0x0e,0x5f,0x2a, -0xb0,0x5e,0x54,0x5f,0x16,0x5f,0xe1,0x06,0x42,0x98,0xa5,0x83,0xca,0xb7,0x7a,0xf9,0x3e,0x54,0x85,0xee, -0xa7,0xa7,0xd9,0x12,0x31,0xba,0x04,0x4e,0x8c,0x4c,0xe7,0xf1,0xd4,0xf4,0x8c,0x09,0xa6,0x2a,0xc8,0x7b, -0x94,0x52,0x3d,0x53,0xeb,0x11,0x33,0x2c,0x1d,0x15,0xb4,0x28,0xe4,0x3a,0xfe,0x4e,0x9e,0xef,0xb3,0x84, -0x77,0xeb,0x4a,0x6c,0xa3,0x2e,0x1a,0x72,0x61,0xfd,0xb3,0x5d,0xba,0x90,0xc0,0xdd,0x94,0x36,0xdd,0x82, -0x9e,0xa8,0x60,0x66,0x23,0x88,0x84,0x0a,0x2c,0x14,0xcc,0x56,0xad,0x56,0x37,0xe3,0xe9,0x16,0x1c,0x25, -0xa4,0x86,0x7f,0xa4,0x71,0x71,0x63,0xa9,0x7f,0x47,0xf4,0xd4,0xfd,0xd2,0x78,0xa5,0x14,0x47,0x22,0xa9, -0x52,0xd4,0xa1,0x48,0xab,0x93,0xec,0x58,0x2c,0xaa,0xfd,0x5c,0xbd,0x98,0xa3,0x91,0x54,0x89,0xf2,0xec, -0x33,0x75,0x62,0x4e,0x49,0x52,0xa5,0xb8,0x73,0x92,0x54,0x2b,0xc9,0x49,0x49,0xaa,0x17,0x77,0x56,0x92, -0x6a,0x45,0x9c,0x96,0xe4,0x2a,0x61,0xe7,0x25,0xb1,0xce,0x0b,0x90,0x19,0x71,0x66,0x92,0xaa,0x44,0x9d, -0x1a,0xbf,0x0e,0x5d,0x37,0x49,0x2f,0x62,0x5e,0x8f,0xff,0xc6,0xf7,0x7e,0xc2,0x8b,0x41,0xac,0x3d,0xba, -0xe3,0x2d,0xaf,0x1d,0xe6,0xad,0x40,0x43,0x56,0x34,0x22,0xe6,0x24,0xcf,0xdc,0x0c,0x35,0xa1,0x12,0xcb, -0x57,0x49,0x78,0x11,0x07,0x48,0xbc,0x11,0x00,0xc9,0xef,0xc6,0xc4,0x75,0xb5,0x21,0xe1,0x03,0xbd,0x28, -0x07,0x8b,0xb9,0x53,0x49,0x80,0xfb,0x33,0x8e,0xc7,0x44,0xd2,0xe7,0xc9,0xd3,0xb7,0x78,0x2c,0x35,0x22, -0x10,0xc2,0x6e,0xce,0xa2,0x96,0x5c,0xb2,0x49,0xc1,0x6b,0x1a,0x44,0x48,0x76,0xd8,0x92,0x1d,0x44,0x21, -0xa6,0x82,0x34,0xac,0x12,0x86,0x62,0x31,0xd2,0xf7,0x2c,0x10,0xae,0x9f,0xd5,0xc4,0x85,0x2a,0x34,0x2d, -0x87,0xc5,0x2a,0xfb,0x49,0xe9,0x96,0xa7,0xa2,0x9c,0xe8,0x31,0xa5,0x92,0x50,0xe7,0x47,0x24,0x24,0x0b, -0xd0,0x45,0x83,0xc5,0xf1,0x51,0x18,0x4a,0x22,0x82,0xdc,0x17,0xa4,0xa5,0x24,0x8b,0x9a,0x35,0x89,0xb2, -0x55,0xe8,0x65,0x0a,0x47,0x0b,0x70,0xb0,0xdf,0x00,0x73,0x25,0x25,0x5f,0x96,0x22,0x3a,0x22,0xdc,0x15, -0xcf,0x3c,0xa3,0xd9,0x65,0x89,0x46,0xbe,0x04,0x52,0x5c,0x09,0x27,0x01,0xc6,0x35,0xef,0x77,0xc0,0xa0, -0x4e,0x1e,0x1b,0xd5,0x67,0xba,0x0c,0xe2,0x62,0xcf,0x77,0x2c,0xc5,0xd0,0x10,0xe0,0xf8,0xd4,0xc0,0x81, -0x57,0xf0,0xff,0x25,0x5f,0xad,0x85,0x35,0xe3,0xc2,0xf1,0xa5,0xf0,0xd9,0x6b,0x40,0x91,0xa3,0x6e,0xa9, -0x50,0xbd,0x10,0x9a,0x57,0x40,0x10,0x19,0x35,0x5f,0x89,0xd3,0x19,0xd0,0xc0,0x11,0xf2,0xec,0xf0,0x3c, -0xe2,0x2a,0xe4,0x62,0x35,0x2a,0x17,0x43,0x0b,0xa7,0x1c,0xdf,0xfb,0x8a,0xd5,0x49,0xda,0x25,0x8c,0x55, -0x92,0x37,0x24,0x53,0x2b,0x95,0xf3,0x95,0xd8,0xe6,0x6a,0x42,0xa5,0xaa,0xbf,0x59,0xbc,0xa0,0x52,0x7c, -0x43,0x5a,0xaa,0x94,0x22,0xec,0x5f,0x22,0x9d,0xf9,0xea,0xa3,0x01,0xdb,0x90,0x05,0xb5,0xb6,0xb6,0x96, -0x22,0xe8,0x82,0xbd,0xa7,0x42,0x7d,0x3d,0x22,0x62,0xf9,0x90,0x91,0x25,0x2e,0x75,0x19,0x6b,0xcc,0xb3, -0x79,0xe8,0x56,0x99,0xdb,0x77,0x08,0xb1,0x58,0x56,0x8f,0x9f,0x6e,0xa5,0x34,0x56,0xeb,0x20,0x1a,0x72, -0x3f,0xa4,0x69,0xf3,0x1d,0x89,0x50,0x6e,0xa2,0xe0,0x80,0xf5,0x98,0xcc,0x5d,0x68,0xd6,0xfd,0x6f,0x5c, -0xf8,0xef,0x1d,0x17,0x96,0x5d,0x8e,0x90,0xa5,0x9f,0x98,0x74,0x27,0x49,0xa4,0x38,0xb9,0xa5,0xb7,0x09, -0xf4,0x8e,0xbd,0x95,0x09,0x9e,0xf8,0x32,0x4e,0xf1,0xd4,0x6a,0xa9,0x15,0x42,0x34,0x8f,0xbd,0x0d,0x11, -0x3d,0xf6,0x36,0x4c,0xf5,0xd8,0xeb,0x28,0xd9,0x63,0x15,0xc2,0x74,0x8f,0xbd,0x96,0x08,0x9f,0xf0,0x2e, -0xa0,0x7c,0xfc,0xe5,0xa2,0x09,0x4b,0xb4,0x8f,0xbd,0xa3,0xc4,0x8f,0xd0,0xfa,0x79,0xe3,0x29,0x64,0xc1, -0x25,0x30,0x8a,0x64,0xd4,0xa1,0x94,0xdb,0x4c,0xf3,0x2e,0x7f,0xc1,0x4a,0x7b,0xad,0x28,0x7e,0x81,0x74, -0x66,0x50,0x49,0x62,0x92,0x3a,0xcb,0xa1,0xf0,0x3d,0x78,0xd0,0x75,0x90,0x9c,0x7c,0x70,0xcc,0xe5,0xcd, -0x0f,0x8c,0x47,0xb0,0xf5,0x7c,0xeb,0x88,0x3e,0x6e,0x52,0x99,0x5e,0xa2,0x16,0x52,0x69,0x33,0x6a,0xd5, -0xd0,0x66,0x86,0x47,0xc6,0xaa,0xf4,0x6c,0x1a,0xae,0xf7,0x23,0x66,0x63,0x3d,0x45,0x6b,0xe0,0x5f,0xfc, -0x24,0x02,0xdd,0xbf,0x8d,0x79,0xfa,0xa5,0xe8,0x20,0x52,0xaa,0x85,0x5f,0x99,0xc7,0x18,0x24,0xd4,0xd3, -0xea,0x78,0x3c,0x04,0x6a,0x86,0xc1,0xb2,0xee,0x22,0x08,0x4a,0x4c,0x3f,0x88,0x27,0xa9,0x84,0x3a,0xb6, -0x1d,0xe3,0x3b,0xe0,0x55,0x33,0x25,0x2b,0xe0,0xc5,0x6d,0x94,0x28,0x12,0x92,0xd4,0xe9,0xf3,0x4d,0x13, -0x66,0x97,0x5c,0x31,0x4a,0x9a,0xe4,0x5a,0x2e,0x99,0x68,0x80,0x01,0xdb,0x59,0x98,0xbc,0xb3,0xc8,0x05, -0xf3,0x07,0x8b,0x0e,0xfe,0x23,0x49,0xc0,0xd2,0xb7,0xd4,0x76,0x73,0x22,0xfb,0xf1,0x81,0x69,0xae,0xf5, -0x5c,0xdb,0x9c,0x7a,0x84,0xf1,0x1f,0x45,0x32,0x63,0xc1,0x38,0x9b,0x24,0x73,0x65,0xf2,0x54,0xfd,0x51, -0x25,0xb6,0xa6,0x7b,0xe3,0x8c,0x98,0x3c,0x33,0x46,0xee,0x87,0x25,0x3f,0x7c,0x48,0xe8,0x43,0x46,0x2c, -0x0d,0x9c,0xb2,0xd4,0x14,0x96,0xf5,0x90,0xd4,0x20,0xea,0xb3,0x44,0xe7,0x1a,0x02,0x5f,0x73,0xfd,0x76, -0x1f,0x22,0x5c,0xdc,0xd0,0x06,0x5e,0x90,0x78,0xc4,0xad,0xae,0x1a,0xb5,0xba,0x58,0x9e,0x73,0xe6,0xbf, -0x2a,0xb5,0xad,0x7a,0x46,0x12,0x00,0xf4,0x90,0xce,0x0b,0x18,0xeb,0xf9,0x51,0x43,0x63,0xec,0x66,0xe4, -0x3e,0xc1,0xf2,0xc2,0x03,0x64,0x78,0xb2,0x4c,0x1c,0x2d,0xc9,0xcf,0x1b,0xac,0x74,0xd3,0x2f,0x79,0x14, -0x47,0x71,0x12,0x5b,0xa6,0xae,0x90,0x05,0x4b,0xe3,0x75,0x1d,0x3d,0xbf,0xd4,0x92,0xa7,0x94,0x90,0xbc, -0x26,0xcd,0x92,0xcd,0x49,0x9e,0x25,0x65,0x2b,0xcc,0x30,0xf3,0xcb,0x24,0x61,0xe7,0x1f,0xec,0xf0,0xdf, -0xd1,0x81,0x90,0x9f,0x3d,0x7b,0xda,0x1f,0x85,0xfd,0xeb,0xd2,0x2b,0xe0,0x94,0xce,0x4d,0xd0,0xb2,0x9e, -0xe6,0x84,0x96,0xd8,0xcb,0xd7,0x48,0xa2,0x88,0x50,0x13,0xe5,0x46,0x3c,0x36,0x8c,0x11,0x63,0x21,0x9b, -0x03,0x07,0x8c,0x85,0x5c,0x9f,0x07,0x21,0xe8,0x99,0x0b,0xd9,0x89,0x7f,0x10,0xab,0x4c,0xd5,0xb1,0xef, -0xe2,0x17,0x82,0x4c,0xb7,0x5f,0x9d,0x52,0x62,0xa4,0x58,0x0a,0x5a,0xcb,0x22,0x37,0x7a,0x28,0x6a,0x3a, -0x99,0x10,0xa7,0xaf,0xb9,0xfe,0x06,0x45,0x6d,0xad,0xa6,0xaf,0xad,0x3e,0x45,0xd6,0xce,0x8f,0x60,0xfb, -0x22,0x51,0x06,0x2e,0x8a,0xad,0xd3,0x9a,0x91,0x0c,0xad,0x85,0x3a,0x2e,0x25,0x34,0x13,0xea,0xe7,0x87, -0x9f,0x5b,0x55,0x4b,0x7a,0xad,0x44,0xd7,0x7e,0x2c,0x9d,0x2e,0x7e,0x48,0x71,0xa1,0xcc,0xc4,0x4e,0xa2, -0x80,0x86,0xe2,0x29,0xcf,0x0e,0x85,0xbb,0x40,0x21,0x91,0xc1,0x53,0xad,0xa2,0xa0,0xaa,0x2f,0xa8,0x43, -0x0f,0xbc,0x61,0x9a,0x96,0x74,0x8c,0x91,0x55,0x61,0xe7,0x62,0xc9,0x78,0xe2,0xcd,0xf3,0x7d,0x62,0x9a, -0x6e,0xc3,0x1d,0xd9,0xb3,0xa4,0x1d,0x91,0x1e,0xfe,0x91,0x5b,0x29,0xfc,0xa0,0xaa,0xd4,0x29,0x3f,0xa4, -0x47,0xcf,0x59,0x2a,0xf5,0xda,0xbf,0x17,0xcb,0x8a,0x16,0x3d,0x6a,0xe3,0x47,0xae,0xe8,0x66,0x44,0x2c, -0xf1,0x35,0x34,0x82,0x27,0xe8,0xcf,0x1f,0x47,0x22,0x30,0xc7,0x94,0x64,0x14,0x3a,0x11,0x10,0x61,0x1c, -0xed,0xa7,0x0b,0x4a,0x6a,0x21,0x7a,0x7e,0x70,0x33,0x7a,0x24,0x30,0x2d,0xce,0x27,0xe0,0x49,0x08,0x60, -0x09,0xd8,0x92,0x72,0xbe,0x68,0x46,0x17,0x07,0x27,0xdc,0x13,0x32,0x73,0x12,0xd1,0x4b,0xf8,0x47,0x3a, -0x6e,0x1a,0x33,0xc4,0xa3,0x87,0x46,0xa9,0xcd,0x1e,0x81,0xf2,0x25,0x8c,0x4b,0xeb,0xe6,0x6d,0x5d,0x8f, -0x60,0x19,0xa4,0xb6,0x63,0x4c,0x30,0xb2,0xec,0x34,0xc0,0x8f,0x62,0xf3,0xc9,0x56,0xac,0x7c,0x39,0x97, -0xd8,0xf3,0xbb,0x41,0x05,0xff,0x84,0x7a,0x65,0xb3,0xc7,0x3e,0x7c,0x4c,0xc4,0x37,0x94,0xe2,0x1c,0x25, -0xb5,0xc3,0xb3,0xd2,0x1f,0x00,0x82,0x20,0xec,0xf5,0x21,0xda,0x57,0x12,0x5e,0x65,0x71,0x18,0x99,0x96, -0xfc,0xc6,0xe7,0xa3,0x80,0x53,0xca,0xd1,0x44,0xb9,0x67,0x40,0x95,0xbb,0x7b,0x0d,0xb0,0xef,0x8b,0xec, -0x02,0x80,0xbf,0xc3,0x3d,0x00,0x3c,0x8a,0x14,0x0a,0x20,0x81,0x1b,0xc8,0x03,0x6b,0x35,0x5c,0x02,0x22, -0x80,0x04,0xb2,0x65,0x2c,0xa5,0xc7,0xe3,0x43,0xec,0xb1,0x12,0x7e,0x8e,0x3e,0xae,0x86,0x9f,0xab,0xe1, -0xc7,0xc8,0xdb,0x5a,0xf8,0x71,0x2d,0xfc,0x58,0x0f,0x3d,0x96,0xa2,0x7d,0xc7,0x60,0x89,0x8d,0x5e,0x89, -0x16,0x54,0xa3,0x05,0xab,0xd1,0x82,0x5a,0xb4,0x60,0x2d,0x5a,0xb0,0x1e,0x2d,0xa8,0x47,0x0b,0x36,0x22, -0x05,0x51,0x30,0x2a,0x61,0xac,0x54,0xc2,0x68,0xa8,0x44,0x27,0x5a,0x89,0xce,0xab,0x12,0xeb,0x30,0x3a, -0xaf,0x4a,0x74,0x5e,0xd1,0x0a,0xd5,0x7c,0xe4,0xb1,0x16,0x7e,0x0c,0xa1,0x3e,0xda,0xd9,0x6a,0xb8,0x76, -0x2d,0x42,0x87,0x28,0x0a,0x6b,0xd1,0xea,0x6b,0xe1,0xc7,0xd0,0x58,0x51,0x74,0xaf,0x47,0x3a,0x8f,0x62, -0x7f,0x3d,0xdc,0x3c,0x4a,0x0b,0x7a,0x7e,0x65,0x91,0xfb,0xf7,0xd6,0xd9,0xc8,0x4f,0x32,0x23,0xa4,0x9f, -0xfc,0x4a,0x58,0x4a,0x0b,0xce,0x7f,0xc5,0x57,0x43,0xea,0x29,0xb0,0xf8,0x3a,0x5a,0x74,0x16,0x8c,0x2d, -0xc2,0x84,0xe3,0x60,0x9c,0x8c,0x69,0x27,0xc2,0xe2,0x6b,0x39,0xe5,0x5c,0x18,0xa7,0x58,0xda,0xd1,0xb0, -0xb8,0x88,0x58,0x74,0x40,0x2c,0xce,0x99,0xa9,0xc7,0xc4,0xd8,0xb2,0x4a,0x38,0x29,0x96,0x24,0x49,0x16, -0x9d,0x17,0x13,0x72,0x25,0xed,0xc8,0x58,0x82,0x0c,0x4c,0x39,0x38,0x26,0xe4,0x4f,0xda,0xd9,0xb1,0x24, -0x71,0xb4,0xe8,0x04,0x19,0x5b,0xb6,0x09,0x87,0xc8,0x92,0xc4,0x58,0xda,0x51,0xb2,0x24,0x09,0xb7,0xe0, -0x40,0x99,0x90,0x7f,0x69,0x67,0xca,0x92,0xc4,0x61,0xf2,0xc9,0x32,0x21,0x27,0xd3,0x0e,0x97,0x31,0x31, -0x93,0x70,0xbe,0x2c,0x49,0x42,0x2e,0x38,0x65,0x96,0x24,0x3f,0xd3,0xce,0x9a,0x25,0x29,0x95,0x85,0x27, -0xce,0x84,0xe8,0x4d,0x3b,0x74,0xf6,0x8c,0x32,0x8d,0x49,0xe9,0xc8,0x01,0xb4,0xa7,0x85,0x9a,0x7b,0xb5, -0x2e,0xeb,0xed,0xb1,0x2e,0xf5,0x8d,0x0f,0xb1,0xc7,0x4a,0xf8,0x39,0xfa,0xb8,0x1a,0x7e,0xae,0x86,0x1f, -0x23,0x6f,0x6b,0xe1,0xc7,0xb5,0xf0,0x63,0x3d,0xf4,0x58,0x8a,0xf6,0x1d,0x83,0x25,0x36,0x7a,0x25,0x5a, -0x50,0x8d,0x16,0xac,0x46,0x0b,0x6a,0xd1,0x82,0xb5,0x68,0xc1,0x7a,0xb4,0xa0,0x1e,0x2d,0xd8,0x88,0x14, -0x44,0xc1,0xa8,0x84,0xb1,0x52,0x09,0xa3,0xa1,0x12,0x9d,0x68,0x25,0x3a,0xaf,0x4a,0xac,0xc3,0xe8,0xbc, -0x2a,0xd1,0x79,0x45,0x2b,0x54,0xf3,0x91,0xc7,0x5a,0xf8,0x31,0x84,0xfa,0x68,0x67,0xab,0xe1,0xda,0xb5, -0x08,0x1d,0xa2,0x28,0xac,0x45,0xab,0xaf,0x85,0x1f,0x43,0x63,0x45,0xd1,0xbd,0x1e,0xe9,0x3c,0x8a,0xfd, -0xf5,0x70,0xf3,0x28,0x2d,0xfe,0x75,0x7a,0x9b,0xaf,0x86,0x14,0xbd,0x9d,0xb0,0x94,0x16,0xe8,0xed,0xf8, -0x6a,0x48,0xd5,0xdb,0xf1,0x75,0xb4,0x48,0x6f,0xb3,0x45,0x98,0xa0,0xb7,0x39,0x19,0xd3,0xf4,0x76,0x7c, -0x2d,0xa7,0xe8,0x6d,0x4e,0xb1,0x34,0xbd,0x1d,0x17,0x11,0x8b,0xf4,0x76,0x9c,0x33,0x53,0xf5,0x36,0x5b, -0x56,0x09,0x7a,0x3b,0x49,0x92,0x2c,0xd2,0xdb,0x42,0xae,0xa4,0xe9,0xed,0x04,0x19,0x98,0xa2,0xb7,0x85, -0xfc,0x49,0xd3,0xdb,0x49,0xe2,0x68,0x91,0xde,0x66,0xcb,0x36,0x41,0x6f,0x27,0x89,0xb1,0x34,0xbd,0x9d, -0x24,0xe1,0x16,0xe8,0x6d,0x21,0xff,0xd2,0xf4,0x76,0x92,0x38,0x4c,0xd6,0xdb,0x42,0x4e,0xa6,0xe9,0x6d, -0x26,0x66,0x12,0xf4,0x76,0x92,0x84,0x5c,0xa0,0xb7,0x93,0xe4,0x67,0x9a,0xde,0x4e,0x52,0x2a,0x0b,0xf5, -0xb6,0x10,0xbd,0x69,0x7a,0xfb,0x19,0x65,0x1a,0x93,0xd2,0xaf,0xd2,0xdb,0x6b,0xab,0xb2,0xde,0x36,0x87, -0x52,0xdf,0xf8,0x10,0x7b,0xac,0x84,0x9f,0xa3,0x8f,0xab,0xe1,0xe7,0x6a,0xf8,0x31,0xf2,0xb6,0x16,0x7e, -0x5c,0x0b,0x3f,0xd6,0x43,0x8f,0xa5,0x68,0xdf,0x31,0x58,0x62,0xa3,0x57,0xa2,0x05,0xd5,0x68,0xc1,0x6a, -0xb4,0xa0,0x16,0x2d,0x58,0x8b,0x16,0xac,0x47,0x0b,0xea,0xd1,0x82,0x8d,0x48,0x41,0x14,0x8c,0x4a,0x18, -0x2b,0x95,0x30,0x1a,0x2a,0xd1,0x89,0x56,0xa2,0xf3,0xaa,0xc4,0x3a,0x8c,0xce,0xab,0x12,0x9d,0x57,0xb4, -0x42,0x35,0x1f,0x79,0xac,0x85,0x1f,0x43,0xa8,0x8f,0x76,0xb6,0x1a,0xae,0x5d,0x8b,0xd0,0x21,0x8a,0xc2, -0x5a,0xb4,0xfa,0x5a,0xf8,0x31,0x34,0x56,0x14,0xdd,0xeb,0x91,0xce,0xa3,0xd8,0x5f,0x0f,0x37,0x8f,0xd2, -0xe2,0x5f,0xa7,0xb7,0xf9,0x6a,0x48,0xd1,0xdb,0x09,0x4b,0x69,0x81,0xde,0x8e,0xaf,0x86,0x54,0xbd,0x1d, -0x5f,0x47,0x8b,0xf4,0x36,0x5b,0x84,0x09,0x7a,0x9b,0x93,0x31,0x4d,0x6f,0xc7,0xd7,0x72,0x8a,0xde,0xe6, -0x14,0x4b,0xd3,0xdb,0x71,0x11,0xb1,0x48,0x6f,0xc7,0x39,0x33,0x55,0x6f,0xb3,0x65,0x95,0xa0,0xb7,0x93, -0x24,0xc9,0x22,0xbd,0x2d,0xe4,0x4a,0x9a,0xde,0x4e,0x90,0x81,0x29,0x7a,0x5b,0xc8,0x9f,0x34,0xbd,0x9d, -0x24,0x8e,0x16,0xe9,0x6d,0xb6,0x6c,0x13,0xf4,0x76,0x92,0x18,0x4b,0xd3,0xdb,0x49,0x12,0x6e,0x81,0xde, -0x16,0xf2,0x2f,0x4d,0x6f,0x27,0x89,0xc3,0x64,0xbd,0x2d,0xe4,0x64,0x9a,0xde,0x66,0x62,0x26,0x41,0x6f, -0x27,0x49,0xc8,0x05,0x7a,0x3b,0x49,0x7e,0xa6,0xe9,0xed,0x24,0xa5,0xb2,0x50,0x6f,0x0b,0xd1,0x9b,0xa6, -0xb7,0x9f,0x51,0xa6,0x31,0x29,0xfd,0x2a,0xbd,0x5d,0x2f,0xc9,0x7a,0xfb,0xd1,0x94,0xfa,0xc6,0x87,0xd8, -0x63,0x25,0xfc,0x1c,0x7d,0x5c,0x0d,0x3f,0x57,0xc3,0x8f,0x91,0xb7,0xb5,0xf0,0xe3,0x5a,0xf8,0xb1,0x1e, -0x7a,0x2c,0x45,0xfb,0x8e,0xc1,0x12,0x1b,0xbd,0x12,0x2d,0xa8,0x46,0x0b,0x56,0xa3,0x05,0xb5,0x68,0xc1, -0x5a,0xb4,0x60,0x3d,0x5a,0x50,0x8f,0x16,0x6c,0x44,0x0a,0xa2,0x60,0x54,0xc2,0x58,0xa9,0x84,0xd1,0x50, -0x89,0x4e,0xb4,0x12,0x9d,0x57,0x25,0xd6,0x61,0x74,0x5e,0x95,0xe8,0xbc,0xa2,0x15,0xaa,0xf9,0xc8,0x63, -0x2d,0xfc,0x18,0x42,0x7d,0xb4,0xb3,0xd5,0x70,0xed,0x5a,0x84,0x0e,0x51,0x14,0xd6,0xa2,0xd5,0xd7,0xc2, -0x8f,0xa1,0xb1,0xa2,0xe8,0x5e,0x8f,0x74,0x1e,0xc5,0xfe,0x7a,0xb8,0x79,0x94,0x16,0xff,0x3a,0xbd,0xcd, -0x57,0x43,0x8a,0xde,0x4e,0x58,0x4a,0x0b,0xf4,0x76,0x7c,0x35,0xa4,0xea,0xed,0xf8,0x3a,0x5a,0xa4,0xb7, -0xd9,0x22,0x4c,0xd0,0xdb,0x9c,0x8c,0x69,0x7a,0x3b,0xbe,0x96,0x53,0xf4,0x36,0xa7,0x58,0x9a,0xde,0x8e, -0x8b,0x88,0x45,0x7a,0x3b,0xce,0x99,0xa9,0x7a,0x9b,0x2d,0xab,0x04,0xbd,0x9d,0x24,0x49,0x16,0xe9,0x6d, -0x21,0x57,0xd2,0xf4,0x76,0x82,0x0c,0x4c,0xd1,0xdb,0x42,0xfe,0xa4,0xe9,0xed,0x24,0x71,0xb4,0x48,0x6f, -0xb3,0x65,0x9b,0xa0,0xb7,0x93,0xc4,0x58,0x9a,0xde,0x4e,0x92,0x70,0x0b,0xf4,0xb6,0x90,0x7f,0x69,0x7a, -0x3b,0x49,0x1c,0x26,0xeb,0x6d,0x21,0x27,0xd3,0xf4,0x36,0x13,0x33,0x09,0x7a,0x3b,0x49,0x42,0x2e,0xd0, -0xdb,0x49,0xf2,0x33,0x4d,0x6f,0x27,0x29,0x95,0x85,0x7a,0x5b,0x88,0xde,0x34,0xbd,0xfd,0x8c,0x32,0x8d, -0x49,0xe9,0xa8,0xde,0x8e,0xec,0xb6,0xd3,0x1b,0xd8,0x63,0xa9,0x49,0xc6,0x78,0x08,0x32,0xc8,0x9d,0xd8, -0x96,0x8b,0x37,0x4e,0xa5,0x5f,0x59,0xfb,0xf4,0x0e,0x84,0xa0,0x3d,0xf5,0xd4,0x77,0xf4,0xea,0xf5,0x42, -0x90,0x82,0xe4,0x5f,0xfc,0x8e,0x69,0x16,0x3c,0xc9,0xd1,0x34,0x95,0x42,0xc5,0x55,0x88,0xe6,0x12,0xbc, -0xcf,0x98,0x5d,0xc9,0xb6,0xb8,0x82,0xbb,0xf8,0xbd,0xbd,0xf0,0xf5,0x82,0x77,0x02,0xf0,0x78,0x96,0xb2, -0x48,0x77,0x0e,0xe5,0x56,0x96,0x44,0xfd,0x02,0x4b,0x6c,0x52,0xe8,0x7c,0x59,0x0a,0x69,0xb9,0x86,0x27, -0xce,0x38,0x7e,0xf0,0x77,0xb4,0xae,0x84,0x95,0xa0,0xc1,0x53,0x81,0xa7,0x51,0xfa,0xe7,0x9b,0xe9,0x3d, -0x13,0x41,0x4e,0xab,0xc2,0x2e,0x62,0x7f,0xf4,0x4d,0xaa,0xe0,0x5c,0x9b,0xc8,0xc7,0xa0,0x03,0xcb,0x97, -0x7b,0x97,0xf1,0x76,0x98,0xa7,0x02,0xbb,0x19,0x3f,0x38,0x38,0x2d,0x1d,0x66,0x8e,0x5f,0xab,0x27,0x06, -0xac,0xd0,0xfc,0x1e,0x9a,0x17,0xbe,0xe0,0xc8,0x33,0x66,0x60,0xb1,0xee,0x95,0x51,0xd9,0x3f,0x2b,0xc3, -0x5a,0x05,0x49,0x45,0x98,0x9f,0x27,0x5f,0x3d,0x5f,0xc5,0xec,0x2a,0xd1,0xac,0xf2,0x23,0xf2,0x6a,0x53, -0x4a,0x18,0x8c,0xe6,0x77,0xe7,0x69,0xca,0xaf,0x8f,0xac,0xbc,0x3b,0xed,0xd1,0x3c,0x21,0x3e,0x32,0x62, -0x40,0x01,0x54,0xd1,0x7f,0xa2,0x43,0x8a,0x7e,0xeb,0xf5,0xfa,0x13,0xa3,0x17,0xef,0x93,0x52,0x21,0x1f, -0xa3,0xdb,0x66,0x24,0xef,0x9d,0x65,0x1b,0x73,0x76,0x10,0xc7,0x08,0xfc,0x54,0xe3,0x32,0xa6,0x22,0xc9, -0x97,0xe2,0x97,0x37,0xca,0xf5,0x72,0x5d,0xce,0x08,0x65,0xf9,0x9f,0xcf,0xe4,0x79,0x32,0xd0,0x14,0x71, -0xb9,0xbb,0x7c,0x81,0x1e,0xcb,0x87,0x16,0xe9,0x57,0x6b,0x2c,0x65,0x7f,0x8d,0x5f,0x02,0xc4,0xdb,0xb1, -0x05,0x4b,0x57,0x5f,0xb4,0x40,0x99,0x9a,0x29,0x57,0xac,0x61,0x7e,0x4f,0xac,0x3d,0xe7,0x53,0xcc,0xd9, -0xce,0xeb,0x06,0x7e,0x0d,0x41,0x5f,0xd0,0x65,0x9e,0x9f,0xf4,0x13,0x9c,0x01,0xcc,0x15,0xef,0xd1,0x34, -0x14,0x7e,0x1a,0x32,0xde,0x13,0x7d,0x17,0xcd,0xf4,0x6b,0x24,0xf6,0xe3,0xe7,0x39,0xc6,0x5e,0x24,0xdc, -0xb6,0x06,0x84,0x18,0xd4,0x75,0x7d,0x2d,0xde,0x8b,0x9f,0x0b,0xe8,0xe3,0x1a,0x53,0x2c,0xd3,0x06,0x93, -0xbe,0x5c,0x50,0x2e,0x83,0xd4,0x0b,0x9a,0x48,0x67,0x09,0xa5,0x94,0xcb,0x30,0xef,0x44,0x4e,0x19,0x84, -0x38,0x49,0x02,0x35,0xc2,0x43,0xf2,0x95,0x6a,0xeb,0xb9,0xd0,0xed,0x8c,0xc0,0x9e,0x01,0xe7,0x71,0xae, -0x45,0x09,0x21,0xdf,0x1f,0x1e,0x2c,0x65,0x4c,0x25,0xe4,0xc2,0x20,0x96,0x6c,0x99,0x9e,0x67,0xc9,0xd3, -0x20,0xfd,0x0a,0x0a,0x98,0xab,0x56,0x82,0x84,0x8c,0x24,0x64,0x87,0xeb,0xab,0x91,0x67,0x96,0x34,0x1e, -0x2b,0xed,0x91,0x81,0xed,0x90,0xe4,0xb4,0xd7,0xcd,0xb8,0xb2,0x61,0xb7,0x43,0xbc,0xa6,0xe7,0xf8,0x39, -0x02,0x49,0xa2,0xe4,0xe9,0x35,0x5a,0x7e,0x22,0xbb,0x92,0x49,0xee,0xfb,0x87,0xd4,0x84,0x62,0x93,0x7b, -0xbd,0xf1,0xad,0x65,0xde,0x95,0x2a,0x64,0x6f,0x48,0x7b,0x48,0xa7,0xa5,0xf9,0xa5,0x72,0x38,0x1b,0x5f, -0x03,0xc9,0x55,0x99,0x20,0x12,0x3a,0x27,0xa2,0x64,0x16,0xf0,0x9b,0xd4,0x38,0x94,0xea,0xfd,0x22,0x55, -0x14,0x4c,0xcb,0x57,0x37,0x6c,0x5a,0xe1,0xd6,0x69,0xba,0x92,0x77,0x12,0xb1,0x2c,0x0a,0xc6,0xe9,0x08, -0x20,0xd8,0xc6,0xeb,0x4f,0xb6,0x31,0x2d,0xd0,0xc0,0xab,0x52,0x43,0x66,0x01,0xcd,0x9f,0xa6,0xbf,0xf0, -0x7b,0x28,0x55,0x9d,0xb1,0x7e,0x2e,0xe1,0x74,0xf6,0x48,0x08,0x75,0x98,0x5f,0xe4,0x1e,0xd8,0xc8,0xe7, -0x3d,0xc4,0xe2,0xac,0x51,0xc5,0x50,0xa6,0x8a,0xe1,0x29,0x11,0x16,0x76,0x62,0x2c,0x81,0x4f,0x90,0xda, -0x35,0x41,0x05,0x3a,0xa4,0x48,0x95,0x4e,0xeb,0x89,0x9d,0x19,0x4b,0x38,0x1e,0x20,0xad,0xe0,0xf5,0xa8, -0xae,0x5e,0x17,0x79,0xb8,0xc1,0xf7,0x59,0x42,0x17,0xf7,0x67,0xfc,0xdb,0xf9,0x95,0x63,0x32,0x25,0x19, -0x7e,0x47,0x7f,0x70,0x67,0xbf,0x94,0x42,0x1c,0xc1,0x49,0x58,0xfa,0x88,0xab,0x5d,0xd6,0x65,0x15,0xe7, -0xcf,0x96,0xd1,0x9b,0xca,0x0f,0x26,0xa6,0x04,0x3f,0x0a,0x34,0x44,0xbf,0x9f,0x92,0x88,0x02,0x75,0x11, -0x62,0x5e,0x7a,0x17,0xef,0x1d,0x7e,0xdd,0x23,0x56,0x1e,0x1a,0x70,0x27,0x21,0x7b,0x1d,0x94,0x95,0x5c, -0x65,0x8b,0xea,0xa7,0x13,0x2b,0x81,0xb2,0x5c,0x02,0x73,0x16,0x97,0x4e,0x14,0xa0,0xa4,0x89,0xdd,0x40, -0x3a,0x75,0xcc,0x6c,0xf2,0x77,0x0f,0x8d,0xcb,0xad,0x93,0xce,0xac,0xf4,0x79,0x7f,0x68,0xe3,0x47,0xb2, -0x8e,0xbb,0x17,0xa3,0xdd,0x8b,0xe0,0x73,0x87,0xbd,0xed,0xd6,0x35,0x7e,0x54,0xab,0xd7,0xef,0xae,0xd2, -0x2f,0xa0,0x6d,0x8d,0x3f,0x1d,0x76,0x4a,0x67,0xfc,0x6b,0x5c,0x3b,0xb5,0xb3,0x75,0x8f,0x7e,0x4f,0x6f, -0xfb,0xcb,0x56,0xfb,0xea,0xcb,0x11,0xfc,0x72,0xcf,0xe1,0xaf,0xc3,0xdd,0xd9,0x6e,0x6b,0x3c,0x99,0x5d, -0xd3,0x36,0xd5,0xce,0xa7,0xf3,0x8b,0x8b,0x83,0xd5,0xb3,0x76,0x67,0xaf,0x53,0xaf,0x6d,0x3f,0x3e,0x8c, -0x77,0xe9,0x77,0xb9,0x46,0x9f,0x3a,0xbb,0x7b,0x17,0xfb,0xc7,0x47,0xe5,0xdb,0x5b,0xef,0xa4,0x55,0xde, -0xbd,0x38,0xab,0xaf,0x94,0x4f,0xaf,0x36,0xf6,0x87,0x6d,0xa3,0x7d,0xb7,0x3d,0xb2,0xed,0xfd,0xf6,0xb9, -0xb7,0xd5,0x9d,0xed,0x55,0xaf,0x5b,0x97,0x87,0x9d,0xb6,0xf9,0x79,0xbe,0x7f,0x67,0x1f,0xee,0xb5,0xf7, -0x87,0xdd,0xd3,0xd1,0xfd,0xde,0xaa,0x71,0x65,0x1e,0xea,0x0f,0x07,0x5b,0x5f,0xb6,0x2a,0x83,0x2f,0xf5, -0xcf,0xa7,0xad,0xfd,0x2f,0xfa,0x97,0xf5,0xef,0xfd,0xd6,0x7e,0xfd,0xf6,0x4c,0x3f,0x98,0xaf,0x6b,0xc5, -0xf6,0x61,0x9b,0x4c,0xea,0xa7,0xb7,0xb5,0x2f,0xa3,0xd5,0xe1,0xe8,0xd1,0x58,0xb9,0x02,0xb1,0xf8,0x69, -0xeb,0xd1,0xaa,0xb6,0x6f,0xdd,0xd1,0xf5,0xd7,0x9d,0xea,0x76,0xaf,0xbe,0xd3,0xea,0xcc,0xd7,0x47,0xc7, -0x93,0x93,0xca,0xe8,0xf6,0xe8,0xac,0xd2,0xed,0x1f,0xef,0x9c,0xd5,0x4f,0x2f,0x76,0xae,0xbe,0xb4,0x76, -0xee,0x2f,0x86,0x8f,0xa5,0x5b,0xb2,0x6d,0x1c,0xf4,0xcc,0xf6,0xd9,0xdd,0xe5,0xee,0xd7,0xc7,0x8b,0xf6, -0xfe,0xfd,0xdd,0xe7,0xc9,0x97,0xfb,0xcf,0x9f,0x3f,0xf7,0x8c,0xce,0xd6,0xa7,0xcb,0xae,0x71,0xf1,0xb9, -0x5f,0xda,0xaf,0x5f,0xae,0x1e,0xed,0x5a,0xdb,0x27,0xed,0xdb,0xdd,0x93,0xe3,0x87,0xdd,0xbd,0x4f,0xc7, -0xe3,0xea,0xf1,0xac,0x3a,0x9f,0x54,0x87,0x15,0xf3,0x53,0x7f,0x74,0xe6,0x1a,0x2b,0xc3,0xfa,0xe1,0xfa, -0x71,0xe9,0x74,0x7f,0xcd,0xb5,0xd6,0xf7,0xaa,0x7b,0x9d,0xcb,0xce,0xaa,0x59,0x1a,0x95,0xef,0xbe,0x96, -0x46,0xbd,0x5e,0x6b,0xe4,0x5d,0xec,0x5f,0x3d,0xd4,0xbb,0x47,0x95,0xbd,0xd6,0xf6,0xfc,0xcb,0xbd,0x3e, -0x28,0x93,0xf6,0xf8,0xea,0xd3,0xbe,0x39,0x2d,0x8e,0x1f,0x8a,0x5f,0x0e,0x36,0x56,0xee,0xcf,0x57,0xae, -0xf4,0xe3,0x96,0x3e,0x5f,0x79,0xf8,0x54,0xdf,0xfe,0x5e,0xdf,0x31,0x4f,0x6b,0x27,0x97,0x07,0xc5,0x95, -0xda,0xd7,0xc9,0x40,0xa7,0xa4,0xd9,0x35,0xf7,0xce,0xef,0xba,0xd3,0xb3,0xf1,0xf6,0x76,0xe8,0x86,0x5f, -0x87,0x4c,0x88,0x86,0xec,0xc8,0x7f,0x3d,0x51,0xc6,0x96,0xb9,0xee,0x10,0x0b,0x4e,0x2c,0xc9,0xb2,0xf8, -0x5b,0x33,0x54,0xb7,0x75,0x7d,0xb0,0xf6,0xbd,0xdf,0xc7,0x31,0x0e,0x05,0x43,0x1d,0xeb,0x77,0x47,0xe5, -0xcb,0xad,0x9d,0xdd,0xa3,0xe1,0xf7,0x7a,0x6d,0xee,0xb4,0x0e,0x0f,0x0e,0x86,0x25,0x77,0xab,0xd3,0x6a, -0x3f,0x76,0xf6,0xc6,0xb5,0xf3,0x96,0xd1,0x39,0xbc,0xfe,0x34,0x5b,0x3d,0x59,0x6f,0xcd,0x6b,0x27,0x5f, -0x35,0xf7,0x60,0xbd,0x52,0x7f,0xb8,0x1e,0xe8,0xf5,0xe2,0xa9,0x69,0x9e,0x6d,0x6d,0xb7,0x4f,0x5b,0xf5, -0xd3,0xd5,0xbd,0xb5,0xfd,0x7a,0x6b,0xe5,0x74,0xde,0xbe,0xdc,0x5e,0xfd,0xba,0xb1,0x31,0xdb,0xbe,0xf7, -0xce,0xf4,0xf5,0xe9,0x8c,0x6c,0x7d,0x6a,0x8d,0x56,0xbf,0x9f,0x94,0xc6,0xbb,0x5f,0xb6,0x8f,0x57,0xce, -0xfb,0x87,0xfd,0x4f,0x17,0xab,0x2b,0xdb,0xc3,0xcb,0x2b,0x60,0xc2,0xab,0xbd,0x8b,0x0b,0xed,0xac,0xba, -0x71,0xe1,0x7d,0x3a,0x69,0xad,0x0f,0xcf,0x2e,0xbe,0x1c,0x7f,0x9e,0xe9,0x27,0x3b,0x0f,0xd7,0x8f,0xa7, -0xfd,0xda,0xf6,0xc6,0xfa,0xfe,0x5d,0xaf,0xf3,0x58,0x9f,0xde,0xe9,0x2d,0xeb,0xd3,0xe5,0xac,0x7b,0xd9, -0x6e,0x9d,0xac,0xed,0xed,0x57,0xaf,0xb7,0x77,0x5c,0xf7,0xca,0x3b,0x58,0xdd,0xdb,0xdb,0x2e,0x9d,0xf6, -0x76,0x06,0xa5,0xee,0xec,0xb2,0x7c,0xa7,0x5f,0xec,0x56,0x3f,0x9d,0xdd,0x8d,0x86,0xfd,0xfb,0x8b,0xbb, -0xb6,0xb9,0xbd,0x3d,0xfd,0xb2,0xf6,0x70,0xee,0x0d,0x3a,0x4e,0x7d,0xe5,0xf4,0xac,0x72,0x54,0xec,0x7e, -0xad,0xbb,0x17,0xb7,0xc6,0xa7,0xfb,0x5b,0x8a,0x9e,0x56,0xf7,0xe2,0xf2,0xa4,0xf3,0xb9,0xb6,0x7d,0xdd, -0x6e,0x37,0x93,0x88,0xcf,0xfe,0xc9,0x3f,0x32,0x1f,0x4a,0xba,0x81,0xb9,0x12,0xb9,0x61,0x79,0x2d,0x17, -0xf5,0x21,0x85,0x28,0x95,0xfd,0x8f,0xe0,0x52,0x0a,0xee,0xe3,0xa4,0xb1,0x14,0xb7,0xc2,0x64,0x2b,0x01, -0xaf,0xe9,0x4c,0xa9,0x3e,0x18,0x08,0x16,0xac,0xf7,0xf0,0xcf,0xdf,0x9c,0x0b,0xad,0xfb,0xbe,0xf3,0x78, -0x8e,0xbd,0x7d,0xde,0x10,0x5c,0x78,0x79,0xb7,0xeb,0x55,0x66,0xdf,0x5b,0x47,0xad,0x59,0xff,0x62,0x6d, -0xda,0xbb,0x3d,0x1e,0x0d,0xe6,0x07,0x5f,0xbe,0x0f,0x6b,0xe3,0x51,0xad,0x33,0x22,0x57,0xd6,0xc5,0xe8, -0xd0,0xd8,0x32,0xce,0x4a,0x87,0xf7,0xd3,0x55,0x72,0x5c,0xbb,0xea,0x5c,0xef,0xaf,0x0e,0x06,0x8f,0xad, -0x76,0xfb,0xac,0x35,0x98,0x7d,0xff,0xbe,0x72,0xba,0x7b,0x7a,0x5c,0xff,0x64,0xef,0xac,0x5b,0x2b,0x6b, -0xa5,0xc3,0x8a,0x71,0x39,0x38,0xf4,0x06,0x2b,0x07,0x5f,0x77,0x66,0x1b,0x3b,0xe5,0x47,0x32,0xdc,0xe9, -0x1d,0xdc,0xef,0x0f,0xce,0x86,0xad,0xea,0xf1,0xca,0xf6,0xb1,0xdb,0xf7,0x76,0x3b,0xf3,0xf9,0xaa,0x47, -0xda,0xab,0x1d,0x7b,0xbb,0x38,0x19,0xde,0xb5,0xe7,0x9d,0xf5,0xdb,0xfb,0xbb,0xf6,0x5a,0xb9,0xbe,0x55, -0xa9,0xd4,0xab,0x6e,0x7b,0xd7,0x3d,0x2e,0xef,0xe8,0xe7,0xfd,0xcf,0xae,0x31,0x39,0xea,0xb7,0x2f,0xd7, -0xdc,0x93,0xca,0x7e,0x65,0x7a,0x71,0xbf,0x71,0xf0,0xe9,0x68,0xef,0xb2,0xd7,0x9b,0x9b,0xf7,0x77,0xda, -0xe8,0xf2,0xeb,0xee,0xc9,0xe8,0xe8,0xc4,0x38,0xdb,0x3d,0xdb,0xdd,0x19,0x3d,0x7c,0xad,0x0e,0xbf,0xac, -0x6e,0xe8,0xf6,0xea,0xe7,0xf2,0xe9,0xac,0x5e,0xbc,0xab,0x9e,0x9d,0xd6,0xb7,0xcc,0x2f,0xb3,0x8a,0xbe, -0xbf,0xe2,0x16,0xad,0xdd,0x37,0xe2,0xbc,0x4a,0xad,0xa6,0x8a,0xff,0x23,0xff,0xc5,0x2e,0x20,0xe2,0x9c, -0xc6,0xac,0xcf,0x28,0xeb,0x6d,0x3a,0xfc,0x03,0x67,0xa9,0x3c,0x15,0xe6,0x41,0xbf,0x97,0x14,0xd5,0x0b, -0x3c,0x98,0x66,0x67,0xfc,0x9f,0xa4,0x74,0xbb,0xbb,0x3b,0xb7,0xc7,0xed,0xbb,0x2a,0xf6,0x76,0xf6,0x28, -0xb8,0xf3,0xf8,0xee,0x1c,0x94,0x6e,0x69,0xf7,0xac,0xb3,0xb7,0x51,0xdd,0xe8,0x7e,0x5f,0xb9,0xdd,0xfa, -0x3e,0xac,0xec,0xf6,0x47,0x9f,0x0e,0xb5,0xd3,0xa1,0x7b,0xb6,0x65,0x1d,0xb4,0x46,0x8f,0x6b,0xe7,0xbb, -0xa7,0x6e,0xf7,0xf3,0xf1,0xc5,0x70,0xbf,0x3d,0xfa,0xe4,0xea,0xb6,0x3e,0x2c,0xbb,0x86,0xbe,0x71,0x79, -0x7c,0x79,0x59,0x32,0xbd,0xb5,0xe2,0x97,0xb5,0xbd,0x2f,0xc3,0xad,0x03,0x8b,0xac,0x7f,0xb9,0x1a,0xf4, -0xd6,0x7b,0xd7,0xfd,0xdb,0xc7,0x95,0xfa,0x43,0xa7,0xb2,0x32,0x3c,0xf4,0xae,0x0f,0x27,0x7d,0x77,0x6f, -0xe8,0x8e,0xef,0x6a,0x0f,0x3d,0x6f,0x5c,0x19,0x9c,0x9e,0xe8,0x47,0xdf,0x27,0xd6,0xa5,0x66,0x5f,0xdd, -0xad,0xd4,0x6e,0xad,0xef,0x27,0x56,0x69,0xb8,0xd2,0x69,0xcf,0x6f,0xf7,0x07,0xdf,0x2f,0x86,0x9f,0x41, -0x64,0x77,0x8f,0xbe,0x96,0x4f,0xfa,0xe7,0x64,0xff,0x68,0xd4,0xea,0x74,0x8e,0x8f,0x4a,0xe6,0xde,0xa1, -0xbd,0xf2,0xb8,0x7f,0x67,0x6e,0x19,0xfb,0xc3,0xc1,0x69,0xed,0xcb,0xee,0xde,0x6e,0xe9,0xb4,0xbf,0x71, -0xd7,0x69,0x77,0x86,0xdd,0xe9,0xee,0x5e,0xbb,0x73,0x71,0xd6,0x1d,0xdd,0x4f,0xda,0xc5,0xd6,0x43,0x77, -0xad,0x7b,0x57,0x6e,0x1b,0x63,0xef,0xfc,0x6c,0xe7,0x7b,0x75,0xed,0x76,0xb0,0xbf,0x6f,0x9d,0x6e,0xb5, -0x0e,0xee,0xbb,0x17,0xfd,0xdd,0x2f,0x17,0xa3,0xe9,0xde,0xe5,0x35,0xd1,0xae,0xf7,0xaf,0xbf,0x5e,0x8e, -0xfa,0xee,0xe3,0x3e,0xd1,0x6e,0xcf,0xc6,0xda,0xea,0xc9,0x97,0xd5,0x2d,0x7d,0xf4,0x65,0x7d,0xa7,0x3c, -0x3f,0xa9,0xf4,0xbf,0x18,0xb7,0xce,0x74,0x7a,0x78,0xa2,0xad,0xee,0x57,0xae,0x2b,0x97,0xb7,0x83,0xfb, -0xbd,0x4f,0x3b,0xa5,0xf5,0xeb,0xcb,0xed,0xfd,0xb3,0xeb,0x95,0x53,0x7b,0xa3,0x4d,0x1c,0xad,0xd2,0xbb, -0x78,0xf8,0x72,0x70,0x3e,0xec,0x4f,0x1f,0xee,0xbf,0x14,0xbf,0xac,0x17,0x77,0x9c,0xc7,0x36,0xf1,0x46, -0xee,0xb1,0x57,0x1a,0x6c,0x6d,0x1d,0x7f,0x1e,0x16,0x67,0xad,0x8b,0xfd,0xd9,0x8b,0x56,0x46,0xa0,0x90, -0x65,0x36,0x3c,0xd0,0x2c,0xdd,0x8c,0x5e,0x85,0x20,0x5b,0xc1,0x11,0x73,0x39,0xd9,0x05,0x28,0x85,0xcd, -0xc5,0xd2,0xdf,0x9c,0x57,0xbf,0xdf,0x0f,0xdd,0x8b,0x3e,0xf6,0x76,0xfc,0x35,0x90,0xa4,0x3b,0xe5,0xfb, -0x59,0xa9,0x05,0xf2,0x72,0xe5,0x6b,0xf5,0xbc,0x36,0x3c,0xee,0x5c,0xaf,0x9c,0xed,0x6e,0xef,0x9d,0x4f, -0x5b,0x15,0xaf,0xe4,0x4c,0x8e,0x27,0xad,0xef,0xbd,0xcf,0xc7,0xbd,0xc9,0xee,0x1c,0xac,0xb2,0xd2,0xc9, -0x6e,0xeb,0x76,0xb7,0xdf,0xd9,0xff,0x7a,0xde,0x3b,0x58,0xeb,0xaf,0xef,0xba,0x3b,0x3b,0xa7,0xdf,0x1f, -0x1e,0xfa,0xbb,0x77,0x7b,0xed,0xb5,0xd6,0x55,0xb1,0x75,0xd5,0x1d,0x9b,0x5f,0x57,0xb6,0xbf,0x6b,0x5f, -0x27,0x3b,0x5f,0x74,0x7d,0x77,0xf5,0xf8,0x73,0x65,0x5d,0xdb,0xbf,0xff,0x6c,0xad,0x4d,0x2f,0x67,0xf3, -0x7a,0xf9,0xa8,0x7f,0xfb,0xb0,0xde,0xef,0xd5,0x76,0xe7,0x17,0x1b,0x5b,0x1d,0xa3,0x03,0x24,0x74,0x07, -0xb3,0xfb,0x9d,0xd5,0xfb,0xd6,0x68,0xbb,0x3a,0x6f,0x0f,0x8d,0xb3,0x87,0x9d,0xbb,0xbb,0xeb,0xce,0xb8, -0x35,0x3d,0xd1,0xbc,0xc7,0xf2,0xa7,0x75,0xdd,0x9d,0xeb,0x9f,0xb4,0xcf,0x75,0xf3,0xd4,0x7e,0xbc,0x70, -0xaf,0xf7,0xdb,0xdb,0x2b,0x26,0x0c,0x57,0x3f,0xa8,0x4c,0x3b,0x6e,0x71,0x60,0xb7,0xb4,0x15,0xd3,0x9d, -0x9d,0xd4,0x6d,0xad,0xde,0xdf,0x5e,0xbb,0x33,0x4b,0xfb,0xb5,0xde,0xfc,0xeb,0x74,0xb6,0xee,0x7c,0xf6, -0xbe,0xcc,0x3a,0xe6,0x35,0xd9,0x5a,0x9f,0xde,0x6d,0x5c,0x6f,0xe9,0x2b,0xdd,0x53,0xf7,0xeb,0xe3,0xa7, -0x76,0xb7,0xf5,0xb5,0x35,0xaf,0x6f,0x58,0xd5,0xe2,0xf1,0xd9,0x6c,0xa7,0x54,0xec,0x7c,0xb9,0xf5,0xca, -0xe5,0xea,0x99,0xb9,0xba,0x55,0x5f,0x2f,0x76,0x0f,0x5d,0xef,0x61,0xfd,0xba,0x6f,0x1f,0xdc,0xbd,0x8e, -0xc7,0x36,0x63,0x3a,0x38,0xce,0x74,0xdb,0x34,0xa8,0x9a,0x2a,0xfe,0xe4,0x90,0xc6,0xdf,0x5f,0xfe,0xb5, -0x0f,0xef,0xbb,0xe7,0xc5,0x43,0x1c,0xe3,0xd3,0x65,0xc0,0x53,0x7d,0xf7,0xf2,0xb1,0xdb,0x6a,0x77,0x4e, -0xea,0xc3,0x62,0x87,0x74,0x7a,0x17,0xce,0xf7,0xc9,0xf5,0xd7,0xda,0xf6,0xf7,0x96,0x76,0x5c,0x9d,0x0c, -0x4f,0x87,0xdf,0xef,0xa7,0x46,0xed,0xfb,0xc1,0x51,0xa9,0x76,0x7b,0xb6,0x7b,0xb4,0xfb,0x60,0xae,0x5b, -0x5e,0x69,0xef,0xc8,0xeb,0x9c,0x96,0x6b,0x97,0xdd,0xf5,0x1d,0xed,0xec,0xce,0x6c,0xed,0xd4,0xf7,0xf6, -0xec,0xd6,0xd6,0x5d,0xc7,0xfa,0x6c,0x7f,0x75,0xcf,0xce,0xf6,0xa6,0xbb,0x57,0xe5,0xed,0xe3,0xd5,0x8b, -0xeb,0xd2,0xd9,0xc5,0xe3,0x95,0x71,0xf8,0x79,0xf8,0xe9,0x6b,0xb7,0xa5,0x1d,0xee,0xec,0x5e,0xae,0x6b, -0x8e,0xb5,0xbb,0xdf,0xbb,0x3e,0x3c,0x9e,0xf4,0xce,0xdc,0xfb,0x6a,0xe7,0x73,0xb9,0x74,0xbc,0x75,0x6f, -0xe8,0xd3,0x87,0xed,0x4f,0xa7,0xd5,0x49,0xef,0x78,0x50,0xdb,0xef,0x9f,0x7c,0xbf,0xfd,0xf2,0x75,0x6b, -0xfd,0x62,0xb8,0x5d,0xd6,0xfb,0xda,0xa1,0xf6,0x89,0x18,0xf7,0x5b,0x77,0xe3,0xc7,0xc7,0x5b,0x10,0xb0, -0xb7,0x0f,0x2b,0xb5,0x53,0x73,0x67,0x55,0x5b,0xf9,0xbc,0x67,0xd7,0xd6,0xb4,0xf6,0xc3,0x4b,0x0c,0x7e, -0xa1,0x79,0x13,0x28,0xdd,0x41,0x22,0x26,0x10,0x5a,0xa6,0x6e,0xa0,0xf3,0xb8,0x86,0xfd,0x9b,0xd3,0x7b, -0xbc,0x7e,0x3a,0xbd,0xbd,0xa2,0x32,0x44,0x17,0xf4,0x36,0xef,0xce,0xf7,0xa6,0xa3,0x9d,0xd6,0x59,0x47, -0xaf,0x0f,0x2e,0xd6,0xbe,0x7e,0x6e,0xad,0x0f,0x86,0x5b,0x7b,0xe0,0x8c,0xee,0x74,0xc1,0x0c,0xfa,0x3c, -0xbd,0xfb,0x74,0x3c,0xdb,0x3a,0xbe,0x2f,0x4d,0xcf,0x76,0xbb,0x87,0x17,0xed,0xcf,0x6d,0xef,0xf2,0x6a, -0xad,0x32,0x2f,0x8f,0x3b,0x1d,0x67,0xe7,0x18,0x88,0xea,0x8d,0x06,0xc5,0xef,0xc5,0x53,0xed,0xb8,0x53, -0xae,0x76,0x06,0xb3,0xed,0xde,0xbc,0xdc,0xeb,0x79,0xf6,0x55,0xe7,0xeb,0x00,0xf8,0xe1,0xf1,0xe0,0xa8, -0xd8,0x9a,0x93,0xb6,0x79,0x31,0xb9,0x36,0xf5,0xcb,0x52,0xb1,0xb5,0x52,0x1c,0x9f,0x1c,0x93,0xc1,0xe7, -0xf2,0xe5,0x65,0xab,0x37,0xbb,0xb8,0x1b,0x82,0x5d,0xd7,0xdd,0x99,0x7c,0x3e,0xf3,0x7a,0x87,0xfd,0xf9, -0xee,0xb4,0xfa,0x75,0xeb,0xc8,0x6b,0x6f,0x6c,0x5f,0xf5,0xec,0xdd,0xc3,0xbd,0xe1,0xe8,0xbe,0x53,0x37, -0xa6,0x47,0xb7,0x67,0xa4,0x44,0x2e,0xc7,0xd7,0xed,0x2f,0x6d,0xd0,0xda,0x67,0x27,0x5b,0xa7,0x17,0xd7, -0x5d,0xfd,0xe0,0xd4,0x2d,0xed,0xef,0x0c,0x07,0xd3,0xc7,0x8b,0xca,0x59,0x6d,0xa8,0x8f,0x87,0xee,0x60, -0xee,0x56,0x57,0x5b,0x07,0x9f,0x4f,0x6f,0xd7,0x4f,0x06,0x6b,0xa3,0xc3,0x69,0xe9,0x64,0xed,0xb6,0xba, -0xb2,0x5e,0x3c,0xfb,0xd4,0xff,0x7e,0x34,0x6b,0xb7,0xcf,0x77,0x4e,0x8f,0x6a,0xed,0x95,0xbd,0xfd,0xd3, -0x92,0xf6,0xd5,0xbe,0x1e,0x4d,0x77,0x8f,0xac,0xf6,0xfd,0xca,0xfa,0x7a,0xf1,0xbc,0x66,0xae,0xf5,0x26, -0xa6,0xb5,0xd2,0xda,0xf5,0xce,0x4f,0xac,0xc1,0xa7,0xd2,0x65,0xb7,0xff,0x12,0x3e,0x0a,0xf4,0x54,0x24, -0x4a,0xf6,0x92,0xe8,0x73,0xec,0xcb,0x3c,0xec,0x42,0xca,0xc8,0x7e,0x8a,0xff,0x29,0xd9,0x02,0x98,0x6a, -0xc4,0x8c,0xdc,0xf8,0xc0,0xbe,0x99,0x9c,0xc0,0xae,0xfe,0xbe,0x06,0x57,0x76,0x82,0x51,0x43,0xd7,0x29, -0x86,0x3e,0xed,0xbb,0x19,0x6c,0x54,0x88,0xe0,0x39,0xeb,0x5d,0xd1,0x7e,0x24,0x5e,0xa7,0x23,0xdd,0xe6, -0x13,0xdd,0xf3,0x42,0x60,0x87,0x44,0x0e,0xb3,0x4a,0xd7,0x42,0xf2,0x2b,0xf9,0x24,0x8f,0x5a,0xf4,0x54, -0x07,0xbb,0xb7,0x9e,0x78,0xcb,0x60,0xd8,0x42,0xc6,0xfd,0x89,0xe8,0xd7,0x71,0xf0,0x53,0x25,0xf8,0xb1, -0x68,0xde,0xbd,0x1b,0xda,0x4a,0x62,0x61,0xb0,0xf8,0x09,0x7c,0xb9,0x81,0xb8,0x2a,0xd0,0x97,0xe8,0xc1, -0xe5,0x16,0x35,0xde,0xc5,0x53,0x81,0x7f,0xa2,0x64,0x3a,0xc1,0x9b,0xbb,0xd4,0xf0,0x63,0x5e,0xdc,0xa8, -0x95,0xb4,0x6b,0x21,0xaa,0x8e,0x34,0xc0,0xa3,0xe9,0xb7,0x74,0x48,0x0f,0x70,0x2c,0x3d,0x02,0x26,0x2d, -0x7a,0xc3,0xaa,0x28,0x19,0xf4,0xf0,0x3e,0xa8,0x21,0x7e,0xfa,0x54,0xea,0xb5,0xaf,0x55,0xfb,0xd5,0xbe, -0x04,0x0f,0x7e,0x9e,0x88,0x24,0x54,0x09,0xf9,0xa6,0x35,0xa4,0x81,0xf8,0x12,0xd1,0xc4,0xb8,0x23,0x73, -0x55,0x82,0x0b,0x88,0xa0,0x46,0x3a,0xcc,0xf7,0x1c,0x7b,0xe6,0x92,0xc8,0x5e,0x42,0x5f,0x2b,0x95,0xd2, -0xfb,0xd5,0xf5,0xbc,0x45,0x3c,0xc0,0xc3,0x5d,0x68,0x12,0x26,0x01,0x61,0x1f,0xc6,0x4c,0xbf,0x57,0x5f, -0x2d,0xfb,0x0d,0x01,0x2d,0xa2,0x61,0xd2,0x3c,0x22,0xd9,0x37,0x25,0xbf,0xdd,0xd8,0x06,0x9e,0x4a,0x1a, -0xd1,0xa5,0x5f,0x74,0x95,0x7a,0xd2,0x07,0xeb,0xb5,0xf2,0xaa,0xdf,0xd0,0x85,0x1e,0xa1,0x2b,0x37,0x8f, -0x75,0xa6,0x13,0x35,0x56,0xee,0x10,0xd7,0x0b,0x6f,0x66,0x44,0x67,0x1f,0xbf,0xf3,0x74,0xb8,0xe0,0x7e, -0x32,0x71,0x7f,0x75,0x34,0x3a,0x1c,0x9d,0x9a,0x60,0x3b,0x16,0xe5,0x66,0xb7,0xc4,0x3e,0x15,0x4c,0xfc, -0xa2,0x48,0xc4,0x57,0x2b,0x27,0x7c,0xd7,0xe3,0x99,0xfb,0x58,0xd3,0x6f,0xb6,0x97,0xf3,0x05,0xd0,0x01, -0x1c,0x81,0x15,0xfd,0x23,0x51,0x44,0xe0,0x8e,0x2e,0x87,0x31,0x2f,0x80,0xe4,0x11,0xf9,0x9e,0x43,0xb4, -0x3b,0x79,0xe1,0x23,0x6f,0xbc,0xe3,0xe4,0x71,0xfd,0x6f,0xaa,0xca,0x62,0xc8,0x6f,0x1d,0xdd,0x06,0x8f, -0x5d,0x54,0x80,0x7e,0xb1,0xae,0xb9,0x23,0x12,0xdc,0xd2,0x2d,0x75,0x8d,0x8c,0x10,0x11,0x8f,0x63,0x5b, -0x9f,0x9a,0x44,0x65,0x78,0xe7,0x4f,0x91,0x2a,0xc9,0x9f,0x6d,0x67,0x58,0xb2,0xb4,0x31,0x69,0xf2,0xa5, -0x10,0xfe,0x04,0xf0,0xd3,0x3b,0xb1,0x42,0xc4,0x77,0xe6,0xc3,0xb7,0x5d,0xc5,0xcd,0xc2,0x4a,0x29,0xec, -0x9d,0x53,0xba,0xb0,0x6b,0x79,0x99,0x34,0x8a,0x31,0x0e,0xd2,0x20,0xf4,0x4a,0x5c,0xa9,0x4e,0xb5,0xc1, -0x8c,0xf4,0x60,0x3e,0x11,0xb0,0xdf,0xf5,0x1d,0xa2,0x43,0x13,0x43,0x33,0x5d,0xf9,0xdb,0xef,0xf4,0x92, -0xad,0x58,0x8a,0x40,0x60,0xd2,0xf8,0x1b,0xe6,0xab,0xa5,0x94,0x0d,0xf3,0x1a,0xf4,0xc0,0xd6,0x3a,0xfc, -0x90,0x77,0xdc,0x6a,0xa5,0x48,0x00,0x2c,0x5f,0xc1,0x3e,0x28,0xf4,0xae,0x87,0x88,0x4d,0xde,0x58,0xc6, -0xab,0xff,0xa5,0x7e,0x28,0x7a,0xe4,0xb8,0x5a,0x95,0xf2,0x2d,0xed,0x41,0x81,0xbe,0x22,0x9f,0xa1,0xe7, -0x2f,0x68,0xf8,0x22,0xcc,0xa2,0x91,0xc5,0xf5,0x54,0xa0,0x2b,0x25,0x76,0x75,0x33,0x47,0xbd,0x0b,0xb0, -0x84,0xf7,0x03,0x29,0x5d,0xb0,0x5f,0xf1,0x4e,0xfa,0xd2,0x7d,0x30,0x75,0x7e,0x77,0x59,0x98,0xa4,0x74, -0x2b,0x28,0x2a,0xa6,0xde,0x51,0xb5,0x8d,0x02,0x29,0x76,0xf5,0x3d,0xe5,0x7a,0xf9,0x7b,0xd5,0x15,0x9a, -0x65,0x12,0x34,0x08,0xad,0x67,0xb6,0xe2,0x6b,0xe1,0x1a,0x6c,0x23,0x26,0x12,0x8f,0x8c,0x77,0x11,0x57, -0x7d,0xef,0x40,0x93,0x5a,0xa6,0x8d,0xa6,0x86,0x0a,0xbc,0xcc,0x7e,0x45,0xaf,0x93,0xc2,0x5e,0x0a,0xd4, -0xcd,0x8e,0x5c,0xd6,0xc5,0x3f,0x2e,0x20,0x71,0x79,0x82,0xd0,0x89,0x6e,0x1c,0xde,0x9e,0x5d,0x6d,0x9f, -0xe6,0x67,0x57,0x86,0x8e,0xda,0x2c,0xcd,0x95,0xaa,0x50,0x86,0x12,0xac,0x89,0x57,0xbb,0x86,0x76,0xd6, -0x91,0x6d,0xa4,0x6f,0x1f,0x09,0x4b,0x60,0x35,0x62,0x0d,0xd4,0x72,0x09,0x46,0x04,0x4f,0x9a,0x60,0x0c, -0x88,0xad,0xde,0x69,0x9a,0x16,0xb6,0x88,0xa4,0x2c,0x10,0xd0,0x4c,0x21,0x88,0xf9,0x13,0x43,0x47,0x7c, -0x2b,0x33,0xfc,0xe9,0x08,0xec,0x38,0xf6,0x89,0x26,0x01,0x2c,0x1d,0x9a,0x7e,0xdd,0x42,0x0c,0x30,0x22, -0x40,0xc5,0x45,0x2e,0xaa,0xf4,0xce,0x1f,0x9a,0xaf,0x62,0xe9,0x15,0xe5,0xd2,0x3e,0xdb,0xa5,0x4b,0xd8, -0x6d,0x1d,0x00,0x95,0x3d,0x76,0xb7,0x0e,0xa7,0x5c,0x3d,0x86,0xeb,0xe0,0xbb,0xe0,0x32,0xf6,0x36,0xe8, -0x2b,0xdc,0xdd,0x0b,0x97,0xa3,0x30,0x48,0x2b,0x89,0xe2,0xd9,0x57,0x18,0xc1,0xa2,0xe1,0x4a,0x0c,0x3b, -0x97,0x72,0xba,0x58,0x73,0xa5,0x50,0xae,0xb9,0x22,0xa2,0xd3,0x77,0x6c,0x17,0x50,0x69,0x38,0x61,0x94, -0x89,0x4c,0x87,0x10,0xea,0xd7,0xd6,0xd6,0xc2,0xb5,0x4e,0xa0,0x0e,0xb0,0x6e,0xca,0x8e,0x70,0x24,0x1c, -0xb4,0xc0,0x93,0x67,0x69,0x1d,0xfe,0x9e,0xf1,0x5b,0xa0,0x2a,0x0c,0xe8,0x36,0x9d,0xac,0xc8,0x37,0x0c, -0x28,0x53,0x4f,0xdc,0xe0,0x4d,0x91,0xca,0x8d,0x3c,0x7e,0x19,0x12,0xff,0x8a,0x21,0x2f,0x4c,0x18,0x54, -0xa6,0x6c,0x3f,0x2b,0xbe,0x9c,0xe8,0x3b,0x9a,0xc4,0x92,0x06,0x31,0x13,0x8e,0x79,0xdc,0x0d,0x9f,0xe0, -0x36,0x31,0x9f,0xc7,0xa9,0x43,0x1e,0x0c,0x32,0x4b,0x58,0x1f,0x22,0x3d,0x38,0xca,0x70,0x12,0x53,0xc6, -0xb8,0x22,0x79,0xb0,0xd0,0x65,0xe2,0xe1,0x71,0x93,0x5e,0x31,0x4e,0x91,0x6e,0x15,0x0f,0x0d,0x53,0x0a, -0x8f,0x11,0xed,0x70,0x0b,0x4d,0xae,0x97,0x06,0x7d,0x42,0x17,0xaa,0x26,0x7e,0x10,0xee,0x05,0x4b,0x23, -0x81,0x75,0x56,0x93,0x5d,0xa2,0xc4,0x15,0x13,0x9e,0xce,0x8f,0xb4,0xf5,0x13,0xc1,0x28,0x5d,0x47,0x4a, -0xb8,0x69,0xea,0xaa,0x72,0x59,0xa7,0xe9,0xfb,0xf0,0xa1,0xcd,0x07,0x81,0xa1,0xb5,0xc0,0x9d,0xca,0xa3, -0x3f,0x85,0x93,0x55,0xd8,0xaf,0xea,0x9f,0xe0,0xd5,0xd5,0x80,0x7d,0x66,0x2d,0x73,0x32,0xd2,0xba,0xa9, -0x04,0x96,0x96,0xf8,0x2f,0x84,0x6d,0xb6,0x5a,0x2c,0x76,0x73,0x86,0xa1,0x98,0x96,0x79,0x7a,0x55,0x32, -0x68,0x08,0xc6,0xdc,0x3a,0xba,0xdc,0xbd,0x6c,0x9d,0xed,0x6e,0x15,0x07,0xd5,0x0d,0xa2,0x7d,0xba,0x98, -0xbe,0x34,0x6c,0x53,0x3d,0xbb,0xee,0x6c,0xed,0x0c,0x3f,0x6f,0xe8,0x9f,0xf5,0x23,0x3a,0x86,0x59,0xea, -0x5c,0x8e,0x4a,0x67,0x95,0x0d,0xaf,0x77,0x75,0x39,0xd5,0x5b,0x5b,0x3b,0xfd,0xf1,0xe5,0x48,0xdf,0xbf, -0xbc,0x6b,0x1f,0xe8,0x13,0x7d,0x7f,0x38,0xec,0x94,0xcc,0xe3,0x8b,0x3d,0xb2,0xb5,0x33,0xa2,0x91,0x8b, -0x4e,0xf7,0xa2,0xb3,0x75,0xd9,0xba,0xfd,0x72,0x5d,0xbc,0x3d,0x9d,0xb5,0x5b,0x97,0xd7,0x9d,0xc1,0xc6, -0xce,0x6c,0x6b,0xe5,0x61,0x56,0x7c,0x5c,0x7b,0x38,0x3a,0x2f,0xb3,0xe0,0xd2,0xa7,0xce,0x45,0x6d,0xd7, -0xb9,0xfb,0x34,0x1c,0x0e,0x9b,0xcd,0x9c,0xc2,0x74,0x8a,0x22,0xfc,0x63,0x86,0x2b,0x3b,0x2a,0x40,0x17, -0xe5,0x51,0x0a,0xb2,0xcb,0xf9,0x94,0xa2,0xa3,0xb1,0xdd,0x33,0x4c,0x92,0x66,0x08,0xb0,0x5e,0x23,0x81, -0x8b,0x25,0x63,0x3c,0xb1,0x1d,0x4f,0xb3,0x3c,0xff,0x46,0x57,0xa9,0x28,0xbe,0x10,0xd7,0x6b,0xff,0x4e, -0xb3,0x6b,0x85,0xd5,0xbd,0x4a,0x0d,0x88,0x05,0x6b,0xd1,0xff,0xa8,0x40,0x60,0xaf,0x14,0x31,0x04,0xf3, -0xe1,0x3d,0xbd,0xec,0xec,0x3d,0xd8,0x9e,0x8a,0xa1,0x37,0x33,0xc2,0xb9,0xcf,0x28,0x7d,0x90,0x25,0x6e, -0x33,0xc3,0x0d,0xf0,0x0c,0xab,0xc2,0x0b,0x79,0x20,0x04,0x0a,0x99,0xb3,0x05,0x0d,0xf1,0xc7,0x69,0xb4, -0xb1,0xef,0x8f,0x65,0x14,0x4c,0xc2,0xb2,0xad,0x66,0xa6,0x98,0x51,0xc6,0xc4,0x1b,0xd9,0x38,0x96,0xed, -0x7a,0xe1,0x7e,0xa9,0x29,0xa6,0x50,0xdb,0x23,0xfc,0x82,0x45,0x8b,0xa0,0x6c,0x54,0xfe,0xd0,0xdd,0xdd, -0xbe,0xe8,0xb4,0xcf,0xaf,0x61,0x02,0x65,0x28,0xa8,0x7c,0xd8,0xa2,0x29,0x73,0xca,0xd4,0x85,0x99,0x2b, -0xde,0xc8,0x70,0x15,0x1d,0x98,0xbe,0x4f,0x94,0xb9,0x3d,0x55,0x46,0xda,0x03,0x51,0x3c,0x5b,0xe9,0x8f, -0x34,0x6b,0x48,0xef,0xe9,0x83,0xb7,0x03,0x6d,0x6a,0x7a,0x8a,0x98,0xab,0x02,0xcd,0xe9,0x0b,0xcc,0xdd, -0x51,0xfe,0x43,0xd3,0xc7,0x86,0xf5,0x1f,0x05,0xe5,0x1c,0x7b,0xf2,0xeb,0xcc,0x0c,0x13,0x20,0xa3,0x75, -0x82,0x06,0x60,0xf3,0x39,0xb6,0x35,0xfc,0xd0,0x3a,0x55,0x10,0x49,0xca,0xc8,0xf6,0xdc,0x89,0xed,0x21, -0x8a,0x69,0xb9,0x1a,0xaa,0x05,0xa8,0x54,0xe8,0x96,0xcd,0x40,0xeb,0x13,0xbf,0x8e,0x92,0x9d,0x8d,0x88, -0xc3,0x80,0xd5,0xe0,0x5f,0xcb,0x9e,0xe5,0xe8,0x89,0x34,0xb9,0x29,0xf2,0x66,0x1e,0x0a,0xf2,0x20,0x33, -0x14,0x16,0x87,0x71,0xfd,0x1e,0x0a,0x80,0x89,0x0a,0xd0,0x13,0xf0,0x15,0xc1,0xe6,0x10,0xe9,0x26,0xec, -0xf1,0xf0,0x3b,0xea,0xa0,0xc2,0x5b,0x6a,0x5a,0x87,0x4a,0xa7,0xf9,0xb2,0x22,0x9f,0xac,0x5b,0xcd,0x7c, -0x68,0x21,0x4a,0x7c,0x5c,0xbc,0x2f,0xd2,0x46,0x1f,0xde,0x53,0xab,0x5b,0xa1,0xee,0x63,0x86,0x62,0x0d, -0x19,0x20,0xb3,0xa0,0xb3,0x2a,0x74,0xa6,0x50,0xa7,0x5c,0x62,0x34,0x4f,0xeb,0xd1,0x35,0xd4,0xcc,0x94, -0x33,0x34,0xfe,0xd4,0xb7,0xc1,0x57,0x25,0x1e,0x54,0x1a,0x80,0x83,0x17,0x61,0x3d,0xde,0x59,0x29,0x0a, -0x62,0xc2,0xf4,0x13,0xc7,0x57,0xd0,0xdf,0xcf,0x7c,0x38,0x07,0xe4,0x52,0x90,0x0d,0x40,0x22,0x5e,0xa2, -0x1a,0x50,0x1a,0xa8,0x4e,0x89,0x0c,0x4c,0xa3,0xf5,0xfb,0xe0,0xf3,0x32,0x9e,0x0a,0x51,0x4f,0xc9,0xca, -0xbc,0x92,0x53,0x31,0xaa,0xa6,0x00,0xb0,0x36,0x65,0x35,0x16,0xdc,0xc2,0x9f,0x8c,0xdd,0x28,0x33,0x02, -0x95,0x2d,0xe8,0x40,0x11,0xbc,0x82,0x2c,0x64,0x2b,0x03,0x80,0x75,0xa4,0x68,0x8a,0x45,0x66,0xe0,0x38, -0x39,0xe3,0x19,0xb2,0x40,0x88,0xda,0xd9,0x93,0xf3,0x56,0xae,0xf0,0xbe,0xe7,0x7c,0x68,0x7b,0xca,0x78, -0xea,0x7a,0x8c,0xa5,0x35,0x4f,0x31,0x09,0x68,0x7b,0x9f,0x45,0x06,0x98,0x21,0x09,0x5c,0xee,0xc0,0x4a, -0x23,0x8e,0x2b,0xf1,0x17,0xbb,0x21,0xdf,0xa5,0x4c,0xc5,0x1c,0x37,0xf6,0x5b,0xb3,0xe6,0x8a,0x3d,0x40, -0x18,0x5d,0xf4,0x31,0x49,0x1f,0xfc,0x69,0xa9,0x87,0x86,0xf2,0x97,0x5a,0xd8,0x6c,0xfc,0x3f,0x4b,0x1f, -0xff,0xf3,0xdd,0x3f,0xfe,0xfd,0xbf,0x97,0xb5,0xf1,0x64,0xf3,0x9f,0xcb,0xa6,0xb7,0xb9,0x3c,0xf4,0x36, -0xff,0xeb,0x67,0x36,0xf7,0xe3,0xe9,0xdb,0x0d,0x63,0xd5,0x18,0x30,0xe0,0x58,0x29,0xf8,0x25,0x3e,0x7a, -0xb5,0x6c,0x00,0x0a,0xd6,0x95,0xab,0xf8,0xb7,0xcf,0x06,0x55,0x00,0x2d,0x72,0x0d,0x06,0xbb,0xcc,0xea, -0x94,0xcc,0xc9,0xc4,0x7e,0x31,0x3f,0x77,0xa8,0xbb,0xf1,0xe7,0x19,0xba,0x92,0xc6,0xd0,0x0c,0x7e,0x16, -0x89,0x0b,0x75,0xcf,0x8b,0x92,0x23,0xae,0x99,0x0f,0x17,0xb4,0xe0,0x7d,0x91,0xbd,0x87,0x7e,0x82,0xc5, -0x2d,0x23,0xa6,0x88,0x32,0xf7,0x43,0x0c,0x57,0x28,0xa7,0x59,0x4e,0x6c,0x82,0x78,0xd7,0x94,0x91,0x43, -0x06,0xcd,0x0c,0x0d,0x8a,0x67,0x68,0x5d,0xfc,0x75,0x68,0x58,0x77,0x7e,0x6d,0x3f,0xff,0x16,0xea,0x63, -0xf0,0x00,0x3a,0xe7,0xff,0x68,0xc1,0x08,0xb4,0x7d,0x9c,0x38,0xbc,0x18,0xeb,0xc7,0xca,0xc5,0xbe,0x41, -0xe6,0xc3,0x6e,0xf7,0x74,0xea,0x58,0x9a,0x52,0xc2,0xdb,0x33,0x45,0xef,0x53,0x33,0xde,0x02,0xaf,0xc4, -0x46,0x72,0x1b,0xf1,0x57,0x78,0x06,0x40,0x9e,0x50,0x26,0xa9,0x35,0xce,0x0a,0x4d,0x20,0xae,0x74,0xf0, -0x8b,0x63,0xde,0xd4,0xcd,0x7c,0xe8,0x9e,0xb7,0xce,0x2f,0xba,0x74,0x42,0x45,0xd3,0x78,0xc3,0x01,0x86, -0xc4,0x22,0x8e,0x66,0x66,0x3e,0xec,0xef,0x1e,0xef,0x76,0x5a,0x87,0x7f,0x60,0x88,0x99,0x31,0x30,0x32, -0x1f,0xae,0xda,0x7b,0xed,0xe7,0x3b,0x57,0x58,0x98,0x90,0xff,0x93,0x1f,0xdf,0x7b,0xde,0xab,0xc7,0x63, -0x8d,0x8e,0xce,0xce,0xcf,0x5f,0x3d,0x9e,0xe5,0x4d,0x5e,0x3d,0x1c,0x6d,0x73,0x7c,0x7e,0xfa,0xea,0xc1, -0xd0,0x3b,0x9b,0xbf,0x7a,0x38,0xde,0xaa,0x7b,0xd5,0x3e,0xdf,0x3e,0xd8,0x7d,0x01,0x4b,0x44,0x46,0xa5, -0x2e,0xc5,0xab,0x47,0xe5,0xad,0x0e,0xdb,0xfb,0x07,0xe7,0xaf,0x1f,0xd3,0x25,0x16,0xf8,0x17,0xee,0xeb, -0xb9,0x5f,0xb4,0xeb,0xee,0x1e,0x77,0x4f,0x3a,0xaf,0x1f,0x58,0xef,0x7f,0x7f,0xf5,0xa0,0xba,0x3d,0xb6, -0x3d,0x03,0x1b,0xee,0x9c,0x1c,0x9d,0x9c,0xb7,0xb7,0xbf,0xbe,0x7a,0x58,0x43,0xef,0xbd,0x7a,0x58,0xda, -0xa6,0x7d,0xbc,0x77,0x78,0xf1,0x65,0x67,0xeb,0xf5,0xbc,0x34,0x78,0xfd,0x88,0xb4,0x4d,0x67,0x6f,0xab, -0xd3,0xde,0xd9,0xdf,0xfd,0x03,0xeb,0x9e,0xaa,0x2a,0xb0,0xd2,0x76,0x8e,0xda,0xc7,0x41,0xf7,0xc5,0xa9, -0x19,0x92,0xc2,0xf2,0x2e,0x60,0xe6,0xc5,0xca,0x07,0x58,0x02,0xcc,0x0d,0x5f,0xe3,0x28,0xcf,0xb7,0xf3, -0x77,0xf7,0x50,0xcf,0xf2,0x9f,0xaf,0x6b,0x8f,0x9b,0x85,0xd8,0x18,0xff,0x95,0x74,0x5d,0x54,0xe7,0xb3, -0x7d,0xdb,0xcc,0x87,0xe5,0xbe,0x3d,0x99,0x6f,0xe2,0x05,0xcb,0x6b,0x79,0xf8,0x6b,0x1d,0x6d,0xa5,0x2f, -0x36,0xd8,0x34,0xa7,0xff,0xdf,0xff,0xeb,0x90,0xef,0xf8,0xe8,0x23,0x14,0x6f,0x56,0x6e,0x14,0x8b,0x1e, -0xe0,0x90,0x38,0x63,0xcd,0x2a,0xf4,0x35,0x0f,0x35,0x36,0x6e,0x3d,0x36,0x33,0x7f,0xf5,0x4c,0x0d,0x95, -0x5b,0x52,0x2d,0x8a,0xd8,0x68,0x57,0x78,0x49,0x73,0xcf,0xf0,0x7a,0xd3,0xfe,0x1d,0xf1,0x0a,0xb6,0x33, -0x2c,0x3e,0xc2,0xc0,0x60,0xd4,0x90,0xef,0x45,0xe2,0x4e,0x50,0x95,0xc5,0x7b,0x17,0x3a,0xee,0x3f,0x95, -0x2d,0xd1,0x54,0x74,0xbe,0x7f,0x7a,0xf8,0x50,0x55,0x4c,0x76,0x0f,0x34,0x1d,0x2d,0xa4,0xd6,0xa3,0x18, -0x08,0xfc,0xb0,0x14,0x27,0x8a,0xfb,0x74,0xb2,0x82,0x4b,0x75,0xab,0xb8,0xe2,0xe3,0x4e,0xd5,0xf6,0xd4, -0xc1,0xcb,0xc5,0xd1,0x98,0x1d,0x18,0xc3,0x29,0xdb,0x11,0x7f,0xc6,0xd1,0x40,0x5f,0x30,0xea,0xf9,0x29, -0xfe,0x2f,0xf1,0x39,0xa1,0x98,0x4b,0x82,0x30,0x52,0x61,0xeb,0x66,0xa2,0xd6,0x0a,0x95,0x86,0x09,0xc5, -0xe0,0xcc,0xc1,0x9c,0xe2,0x2f,0xc6,0xda,0xd0,0x32,0xbc,0xa9,0x4e,0xdc,0x85,0x1e,0x01,0xdd,0x56,0x49, -0xf4,0x2b,0xca,0xf9,0x4a,0xd4,0x58,0x3c,0xd2,0xac,0x29,0xd8,0xfc,0x1e,0x94,0x3a,0xe9,0x7d,0xe2,0x91, -0x6a,0xb9,0x25,0x1e,0x0a,0x8f,0x98,0x3b,0x34,0x66,0x90,0xe1,0xe6,0xe5,0x58,0xea,0x35,0x13,0xd8,0x51, -0x69,0xdd,0xc7,0xc1,0xda,0xa1,0x6e,0xc5,0xdb,0x01,0xc4,0xdc,0x94,0x5f,0x02,0x65,0x7b,0x64,0x4c,0x94, -0xf6,0xce,0xdb,0xc1,0xd2,0x87,0x0e,0x0d,0xfd,0x97,0x60,0x39,0x6a,0x6d,0xbf,0x25,0x91,0xfa,0xbf,0x04, -0xc4,0x31,0xdb,0xad,0x7d,0x3b,0x40,0xf8,0xf6,0xef,0x2f,0x01,0xd3,0x3e,0x7d,0x6b,0x26,0x31,0x26,0xbf, -0x04,0xc8,0x9e,0xf0,0x6f,0xb1,0xaf,0xb7,0x83,0x49,0x9b,0x4c,0xfe,0xc2,0x5f,0xbf,0x07,0x13,0xb8,0xdc, -0x2e,0x95,0x70,0x6f,0x09,0x16,0xef,0xf4,0xf7,0x20,0xeb,0x4d,0x0d,0x53,0x7f,0x5b,0xb8,0x68,0x97,0xbf, -0xb6,0xd4,0xb9,0x5a,0xc0,0xaf,0xdb,0xbd,0x1d,0x4c,0xd8,0xdb,0x2f,0x81,0x73,0x31,0x79,0x5b,0x40,0xa6, -0x93,0x5f,0x06,0x65,0xcf,0x21,0x44,0x01,0x85,0x3a,0x79,0x3b,0x68,0xb0,0xb7,0x8c,0x82,0x61,0xd2,0x66, -0x46,0xe9,0xcd,0x3d,0xa6,0xd5,0x7e,0x9d,0x93,0x70,0xe3,0xf4,0xed,0xa0,0x73,0xc1,0x6e,0xe9,0x8f,0xfe, -0xc2,0x4e,0xdf,0x02,0x48,0x44,0x1f,0x3d,0x7d,0xfa,0x76,0x10,0x0e,0xa0,0xcf,0xb7,0x82,0x0f,0xbd,0x5c, -0xa5,0x4b,0x6d,0xa8,0x37,0xd4,0x2f,0xe0,0x40,0x77,0xb9,0x5d,0x76,0x7c,0x72,0xae,0xb4,0x2e,0x5b,0xed, -0xc3,0xd6,0xd6,0xe1,0xee,0xaf,0xe8,0x9c,0xf3,0xd3,0x37,0x87,0x0f,0x3c,0xee,0x17,0x80,0x27,0x62,0x4e, -0x41,0x28,0x2a,0x1e,0x7e,0x0a,0xed,0x13,0xa0,0x47,0xf1,0x9a,0x3d,0x02,0x85,0x58,0x7d,0x16,0x64,0x1b, -0x4f,0x4d,0xcf,0x98,0x68,0x8e,0x47,0x87,0xc8,0xa3,0x13,0x94,0x60,0xfc,0xca,0x66,0xaf,0x1f,0x76,0x49, -0xb3,0x7b,0xfd,0x70,0x0c,0x37,0x7c,0xf7,0x59,0x83,0xb0,0xe1,0xab,0x3c,0x68,0xe6,0x14,0x43,0xee,0x7f, -0x38,0xd0,0x7e,0x00,0xd3,0x65,0xda,0x31,0x21,0x22,0x39,0xe2,0x2f,0x17,0x05,0x24,0xcb,0x41,0x40,0x12, -0xb3,0x61,0x02,0x9c,0x72,0xaf,0x2a,0x14,0x6d,0x7f,0x3e,0xb0,0x5e,0x59,0x60,0x46,0xff,0x7e,0x08,0xde, -0x70,0xe9,0xcc,0xd8,0xde,0x8a,0x41,0x33,0xba,0x06,0xf3,0xd0,0x0e,0x8e,0x61,0xe1,0xbe,0x88,0xa3,0x70, -0xfb,0x47,0xc9,0x72,0xcf,0x0c,0xc3,0xd0,0x02,0x1d,0x18,0x8e,0x2e,0xd0,0x0f,0xd0,0xe6,0x0a,0xca,0x1e, -0xdd,0x99,0x81,0x0e,0x78,0x7a,0x23,0x0d,0xc2,0x6b,0x77,0x44,0x21,0x83,0x01,0xc6,0xe4,0x71,0x97,0xc5, -0x1d,0xd9,0x53,0x53,0x57,0x30,0xef,0x11,0x38,0x89,0xc6,0xe8,0x31,0x72,0x26,0x45,0xf7,0xfb,0xe0,0x81, -0xdd,0xb1,0xdd,0x24,0xa2,0x64,0x7c,0x2f,0x36,0xc3,0x5d,0xd4,0x37,0x8a,0x42,0xef,0xd8,0x53,0xfa,0xd9, -0x2d,0x1c,0x0c,0x26,0x0c,0x0e,0x50,0x22,0xd9,0x7b,0x9e,0xb5,0x43,0x43,0x51,0x2f,0x23,0x3b,0x8b,0x98, -0xc7,0x09,0x3f,0x36,0xe0,0xa1,0x94,0x01,0xdf,0x87,0x4c,0x80,0xf8,0x25,0xf8,0x39,0xd6,0x1e,0xe9,0xaf, -0x92,0xcc,0x16,0x6b,0xff,0x62,0xb6,0xa0,0x73,0x45,0xc2,0x8f,0x81,0x2b,0x0c,0x17,0x71,0xaf,0xbb,0x48, -0x46,0x9d,0x78,0x48,0x41,0x4d,0xd1,0x65,0xbc,0x65,0x07,0x8e,0x8d,0xd9,0x82,0x50,0x01,0x67,0x32,0x76, -0xd9,0x5e,0x09,0xee,0xef,0xd0,0x0d,0x08,0xc6,0x0d,0x0c,0x29,0x94,0x9c,0x03,0xfa,0xe1,0xa4,0xd0,0xce, -0x0c,0xb2,0x1f,0xbb,0x30,0x8a,0xee,0xfa,0xf8,0x11,0x0a,0xe8,0x9f,0xe6,0x4b,0xd3,0xca,0x23,0x8d,0x66, -0x1f,0x18,0x9e,0xbf,0x15,0x08,0x55,0xc1,0xaf,0x8f,0x00,0x54,0x50,0xda,0x56,0xdf,0xc1,0x8b,0x9a,0x42, -0x23,0x1b,0x03,0x7f,0x83,0x6f,0xa4,0x3d,0x50,0xd6,0x72,0x58,0x2b,0x9c,0x99,0x3c,0x21,0x1c,0x8b,0xb3, -0x99,0xd2,0x25,0x1e,0xeb,0x85,0x8a,0x1f,0xac,0x4a,0x27,0xca,0x73,0x59,0x23,0xe3,0x5e,0x43,0xff,0x33, -0xdb,0xfa,0x0f,0x0f,0x61,0xd3,0x78,0xd7,0x2e,0xf1,0xe4,0xa9,0x4a,0xfb,0x4f,0xe8,0x80,0x6a,0xa6,0x39, -0xa7,0x13,0xa4,0x8b,0x2c,0x09,0x1d,0xc6,0x98,0x5e,0xae,0xe1,0x11,0xa8,0x18,0x45,0x0d,0x45,0x34,0x1d, -0x15,0x5b,0x88,0x8d,0x56,0xb1,0x7b,0xc3,0xf8,0x4e,0x1a,0x5c,0xda,0x06,0xc2,0xdb,0x49,0xd8,0x36,0x26, -0x62,0x62,0x90,0xb0,0x66,0xc1,0x4a,0x35,0xe7,0xcf,0xac,0xb3,0x48,0x64,0xce,0xa4,0xa1,0x85,0x17,0xad, -0xbc,0xc3,0xdd,0x1d,0x8a,0x04,0x7f,0xbd,0xb1,0x4c,0x3f,0xbe,0xe0,0xa0,0xa3,0x23,0x78,0x59,0x7a,0x7e, -0xc1,0xf9,0x8b,0x66,0x1d,0x46,0xb6,0x27,0x81,0xa6,0xa0,0xd2,0xf5,0xca,0xd8,0x33,0x14,0x97,0xab,0x64, -0xf6,0x36,0x5a,0xab,0xc4,0x0d,0x0b,0x20,0x06,0xe8,0x10,0x3d,0xad,0x1a,0x35,0xe2,0x80,0x1a,0xa8,0x18, -0x92,0x6b,0xd4,0xa0,0x23,0x4c,0x2c,0x48,0x7b,0x0f,0xab,0xba,0x65,0xce,0xb4,0xb9,0xab,0x9c,0x1c,0xa7, -0xd5,0x59,0x0f,0xea,0xec,0xed,0x05,0x95,0x8a,0x0c,0x39,0x7f,0x03,0x65,0x21,0xf8,0x43,0x27,0x03,0xc3, -0x22,0x2e,0x5b,0x2a,0x04,0xd7,0x13,0xb2,0x2f,0xdb,0xca,0x54,0x30,0xcc,0xa9,0x20,0x81,0xe1,0x1f,0x5a, -0xc1,0x86,0x85,0x4b,0x59,0xf5,0x8a,0xef,0xc0,0x66,0x24,0xc2,0x64,0x82,0x05,0x4d,0x6f,0xcf,0xd1,0x3c, -0xa5,0x7c,0xf0,0x9d,0x6d,0xd6,0x7a,0xce,0x9c,0x73,0x23,0x97,0xff,0xf0,0x04,0xcb,0x7b,0xa0,0xb8,0x53, -0xba,0x2f,0x3c,0x98,0xe2,0xf2,0xe1,0xef,0x88,0x8e,0x6b,0x9c,0xf5,0xe4,0x18,0x64,0x00,0x6f,0x4c,0xe8, -0x9a,0x80,0x0b,0x38,0x57,0x6a,0x8a,0x90,0x63,0x50,0x07,0x20,0xe8,0x9e,0xb7,0xfc,0x4d,0x60,0x56,0x83, -0xbd,0xe7,0xaf,0xf9,0x12,0x0d,0x03,0x2d,0xf3,0x49,0x86,0xb5,0x9e,0x8b,0xb5,0x97,0xb0,0xe0,0x11,0x03, -0x3c,0x7b,0x98,0x58,0xb8,0xb7,0x06,0x72,0x8a,0x7f,0x6c,0x1b,0xab,0x65,0x50,0x83,0x62,0xce,0xcf,0x5f, -0x9e,0x3d,0x31,0xfa,0xa8,0x43,0x8b,0xc0,0xf7,0xc5,0x12,0x50,0x1b,0x94,0xc5,0xcc,0xf0,0x70,0x57,0x7a, -0xa2,0xcd,0x31,0x65,0x16,0x51,0x5b,0x52,0x95,0x32,0x82,0x5b,0x51,0xb2,0xa8,0x52,0xed,0xe1,0x10,0xc6, -0x33,0xbc,0x5c,0x18,0x48,0xce,0xa5,0x1c,0x3e,0x01,0x87,0x80,0xf1,0xe4,0x98,0x21,0x56,0xa3,0x02,0x06, -0x03,0x7e,0x54,0x20,0x02,0xb7,0xf1,0x6c,0x0b,0xf8,0xdf,0x98,0x68,0x16,0xdd,0x3a,0x47,0x8d,0x8e,0xd0, -0x03,0x28,0xfd,0x11,0x10,0x1b,0x28,0x63,0xa1,0x6d,0x1a,0xc1,0x0a,0x32,0x3d,0x1f,0x4e,0x50,0x72,0x60, -0xe3,0xc7,0x8c,0xe9,0xe8,0x12,0xa5,0xa9,0x9c,0xa3,0xef,0xe1,0x79,0x0e,0x2d,0x5c,0x0f,0x68,0x04,0xdc, -0x4f,0x41,0x0a,0x83,0xa3,0xd2,0x9d,0x6a,0x5e,0x05,0x9e,0x39,0xd8,0xfe,0x7e,0xf9,0x18,0x21,0x3d,0x39, -0xa6,0xa0,0x64,0xfc,0x75,0x95,0xa1,0xad,0x32,0xc1,0x1a,0x62,0x70,0xb1,0x5e,0x61,0x11,0x0d,0xf2,0xe4, -0x71,0x62,0x02,0x05,0x3d,0xdb,0x79,0xa5,0x6c,0xd3,0x4c,0xf2,0x18,0xb5,0x74,0x53,0x64,0x1b,0x93,0x80, -0xb0,0x92,0xa1,0x05,0x35,0x69,0x86,0x22,0x76,0xcb,0x65,0xdd,0x4b,0x16,0x1e,0xeb,0x89,0x59,0x21,0xcc, -0xac,0xe8,0xe3,0xd9,0xc1,0x9e,0xfd,0xe8,0x87,0x11,0xb0,0xff,0x5d,0x8b,0x9e,0xa9,0x08,0x59,0x95,0xd5, -0xcc,0x87,0x57,0x4d,0x6d,0xf4,0xba,0x79,0x1d,0xd8,0x60,0x30,0xb6,0x5c,0xd7,0x70,0x31,0x35,0xea,0x8d, -0x27,0x35,0x4a,0x9c,0xd1,0x22,0x69,0xf5,0x3f,0x27,0x01,0xc3,0x13,0xa7,0x79,0x05,0xf8,0xb9,0xdb,0xbe, -0x4d,0xe5,0xc7,0x80,0x68,0x18,0x4a,0x2e,0x28,0x6c,0x02,0x94,0x13,0x5d,0xae,0x91,0x35,0x5d,0x97,0x6d, -0x00,0x28,0xa1,0xea,0xfe,0xa0,0x85,0xb2,0xcb,0xb5,0x4d,0x68,0x45,0xd7,0x13,0x4b,0xa0,0xd2,0x14,0x0c, -0xba,0xc3,0x7b,0x93,0x7e,0xb6,0x12,0x65,0xcc,0x98,0xfe,0x9a,0xf1,0x85,0x29,0xac,0x8f,0xed,0x6e,0x57, -0xa1,0xa9,0x64,0x8a,0x6b,0x2b,0x11,0xe8,0xfa,0x1a,0xa6,0x0b,0x39,0x2e,0x93,0x01,0x34,0x8a,0xff,0x3a, -0x86,0xa7,0x5c,0xf1,0x42,0x97,0x29,0x34,0xf2,0xa9,0x03,0xca,0xe1,0x31,0x62,0x48,0x3f,0xa3,0xc7,0x05, -0xf1,0x59,0xdb,0xb0,0xff,0x24,0xf1,0x41,0x2d,0x93,0xe4,0xeb,0xa6,0x4c,0x2a,0xea,0x87,0x8a,0x3d,0xe8, -0x14,0x2f,0x34,0xd8,0x65,0xe6,0x6e,0x68,0x97,0xca,0x3d,0xa5,0xc8,0x24,0xd3,0xab,0xb6,0x61,0x7c,0xd8, -0xd8,0x81,0x20,0x7f,0xff,0x2f,0xbc,0xe1,0x8f,0x9e,0x34,0x07,0x8a,0xbb,0xbc,0x80,0x34,0xda,0xe0,0x79, -0xea,0xc8,0x8d,0x5f,0x46,0x25,0x3e,0x1d,0x77,0x6e,0xf5,0x17,0x58,0x5e,0xb4,0xcb,0x2e,0xd4,0x79,0x3e, -0xe7,0xc6,0x27,0x4b,0x35,0x66,0x7a,0x81,0x51,0x75,0x6c,0xd3,0xa1,0x46,0xb6,0x05,0xcc,0xca,0x50,0x96, -0x6c,0xf3,0x80,0x99,0xf6,0x95,0x38,0x36,0x6a,0x36,0x4c,0x37,0x0a,0xb4,0x0d,0xbd,0x33,0x2e,0xad,0x15, -0xac,0xf3,0x13,0x8b,0x2d,0xb2,0x5b,0xcc,0xc8,0x0a,0x9a,0x3e,0xd3,0xb0,0x8a,0x26,0x96,0x19,0xc0,0x26, -0x1b,0x6c,0x2f,0xb6,0xb3,0x7e,0xc5,0xa7,0x42,0x83,0x49,0x19,0x71,0xad,0xa8,0x1b,0xe0,0x0c,0xd3,0x30, -0xae,0x3f,0x5f,0xee,0x13,0x83,0x92,0xa6,0xb0,0x81,0x9d,0x6e,0x7c,0x27,0x7a,0x7c,0xcd,0xfa,0x7b,0x75, -0xdb,0x94,0x21,0x7f,0x67,0x45,0x88,0xfc,0x88,0x94,0x15,0x21,0x32,0x20,0xf8,0x7a,0x38,0x44,0x19,0xe4, -0xfe,0xda,0x3a,0x48,0xf2,0xd0,0x5f,0xae,0x71,0x2e,0x5c,0x2e,0xc1,0xc0,0x4e,0xba,0xc3,0x2d,0xc0,0x37, -0x55,0x39,0x53,0x97,0x6c,0x53,0x44,0x48,0x0e,0x3b,0xda,0x5c,0x32,0x8b,0xd7,0xff,0x16,0x0a,0xc8,0xc7, -0x83,0xc2,0x10,0xe1,0x67,0xc1,0xd2,0xef,0x64,0x2b,0x55,0x45,0xec,0xca,0x2a,0x9a,0xab,0x74,0xf6,0xb7, -0x98,0xa1,0x86,0x06,0x97,0x6d,0x81,0x19,0x45,0xe3,0x37,0xc6,0x40,0xd6,0x44,0x23,0xcd,0x0d,0x52,0x07, -0xab,0xc0,0x96,0xe3,0x31,0xfb,0x10,0x39,0xef,0x88,0xf6,0xd0,0xa1,0xe8,0xa0,0xcd,0x26,0xdc,0x78,0x65, -0x99,0x09,0x2c,0x70,0x23,0x67,0x65,0x3e,0x1f,0x97,0x79,0x1d,0xd5,0x61,0x12,0xca,0x9f,0x22,0x3a,0xf4, -0xbd,0x88,0xe4,0xe5,0xf2,0xdf,0x86,0xe6,0x88,0x85,0x10,0xdd,0x81,0x88,0x84,0x99,0x49,0x4a,0x76,0x62, -0xa2,0x65,0x4d,0x83,0xc6,0xe0,0x91,0xb9,0x39,0x55,0xb1,0x81,0x2c,0xce,0x0c,0x44,0x1b,0x66,0xd1,0x2a, -0x07,0xdd,0x4b,0x25,0x3b,0x9a,0x92,0xbc,0x8b,0xf6,0x09,0x5d,0xb5,0x79,0x2a,0x0b,0x73,0xcc,0x76,0x78, -0x63,0x8a,0xd1,0x4b,0x2c,0x05,0xff,0xbc,0x3d,0xd1,0xae,0xb0,0xfb,0x45,0x64,0xdb,0xf8,0xdb,0x50,0x0d, -0x16,0x27,0xb8,0x70,0xd1,0x25,0x85,0x4b,0x93,0xe1,0x88,0x7a,0x34,0x62,0xe5,0xb2,0xd8,0x0d,0x2c,0x27, -0x17,0xc3,0xb1,0x48,0x70,0x4a,0xa3,0x57,0xae,0xe0,0xd5,0xbf,0xdf,0x0a,0x1e,0x6a,0x00,0x10,0x70,0xaf, -0xe3,0x90,0xfe,0x1f,0x70,0x82,0x80,0x25,0xf6,0x71,0x84,0xd0,0xca,0x2d,0xfd,0x6d,0x78,0x20,0x3a,0x7b, -0x2a,0xb1,0xe9,0x72,0x96,0xc9,0x13,0x27,0x30,0xce,0x4b,0x56,0x79,0xc0,0xf1,0x3d,0x70,0x33,0xd0,0xe9, -0xa5,0x39,0xee,0xe8,0xf9,0xbe,0x2d,0x9d,0x7c,0x5f,0xe2,0x0f,0x68,0xd7,0x6e,0xf7,0x6f,0x2a,0x58,0x03, -0x07,0x0a,0x56,0x84,0x43,0xf0,0xb4,0x0f,0xc3,0x3a,0x0d,0x77,0xd3,0x78,0x0f,0x5a,0x98,0x9d,0xdd,0xee, -0xb9,0xd2,0x3a,0x6d,0xf3,0xb5,0x14,0x1c,0x45,0x61,0x4d,0xf0,0x46,0x70,0x57,0xc9,0xbc,0xdb,0xdb,0x2b, -0xd1,0x48,0x3e,0xd0,0xef,0xe4,0x58,0x16,0xc3,0x19,0xbc,0x56,0xaf,0xa4,0x96,0x32,0x6f,0x48,0x33,0x6a, -0xb2,0x28,0xc1,0xd9,0x3c,0xf7,0xed,0xe9,0x76,0x1e,0x74,0x1e,0xa2,0xdf,0xcb,0xa9,0xf2,0x27,0xe9,0xd7, -0x0e,0x74,0x20,0xd3,0x8d,0xec,0x7c,0x91,0xeb,0x13,0xc7,0x1d,0xdb,0x48,0x82,0x88,0x09,0xfd,0x0b,0x66, -0x32,0x4f,0xee,0x4c,0x33,0x93,0x69,0xd2,0x67,0xbb,0x7b,0xde,0x69,0x9d,0xb7,0x31,0xb4,0xcb,0xcd,0x65, -0x96,0x1d,0x26,0x1f,0x71,0xc1,0xf5,0x4f,0xa3,0x02,0xa4,0x3f,0x75,0x0c,0x6f,0x2e,0xa2,0xa9,0x7f,0x7e, -0x53,0xf3,0x8f,0x9e,0x1e,0x5a,0xb0,0xbf,0xf9,0xbf,0xc7,0x89,0xfe,0xf7,0x38,0xd1,0xff,0x05,0xc7,0x89, -0x16,0x70,0xf8,0x33,0xe7,0x8b,0x7e,0x79,0x42,0x07,0xe7,0xe7,0xa7,0x0a,0x2a,0x97,0xc4,0xa9,0x00,0xeb, -0x9e,0xc2,0xbb,0xb7,0x4a,0x43,0xa8,0xfe,0x1d,0xf2,0x10,0x0c,0xb6,0x9b,0x44,0x75,0xb0,0xf0,0x6b,0xc3, -0x4b,0x14,0x99,0x0d,0xb4,0x30,0x68,0xdd,0xfb,0x29,0x71,0x3d,0x97,0xee,0x04,0x05,0x91,0x14,0x0f,0xe4, -0xbf,0x52,0x2f,0x29,0x59,0x0c,0x43,0xea,0x1a,0x2c,0x7c,0x1f,0x89,0xb9,0x60,0xa3,0x66,0x24,0x85,0x64, -0x71,0x77,0xe8,0x71,0x62,0x1a,0x7d,0xc3,0x63,0x9b,0xab,0x34,0x2a,0x2b,0xba,0x6f,0x28,0x3c,0xd5,0x61, -0x3c,0x37,0x26,0x8d,0xf1,0x1c,0x3b,0x2a,0xbe,0xa1,0x06,0xe7,0x71,0x62,0x0a,0x24,0x4c,0xeb,0xad,0x77, -0x07,0x26,0x86,0x88,0xa4,0x3f,0xb3,0x1b,0xf0,0x2a,0xa0,0x3b,0x04,0x44,0x0a,0x66,0xe8,0xfd,0x19,0x90, -0xb1,0xfb,0x73,0x9e,0xff,0xf7,0x2f,0xb7,0x30,0xb6,0xe6,0xe2,0xa0,0xb2,0xaa,0xb8,0x18,0xe3,0x0e,0x72, -0xdb,0xe9,0x86,0x52,0x8f,0x60,0xb4,0x7e,0x02,0x46,0xa0,0x63,0xa3,0x5a,0x41,0x3b,0x10,0x58,0x74,0x60, -0x98,0xc0,0xb1,0x5c,0xdf,0x3c,0xd8,0x06,0x28,0x7c,0xe8,0xdd,0xb0,0xa7,0x3c,0x89,0x80,0xf1,0x2d,0x65, -0x48,0x1e,0xcf,0xc7,0x1c,0x06,0x07,0x66,0x9e,0xa7,0x88,0x65,0x95,0x40,0xca,0xdb,0x5e,0xa8,0xf3,0x9c, -0xd8,0x4f,0xc5,0x35,0x00,0xae,0xbc,0x85,0x5b,0x67,0xf2,0xae,0xfd,0x1b,0xc9,0x52,0xc1,0x90,0xca,0x67, -0x92,0x9c,0x0e,0x03,0x74,0x82,0x57,0x51,0xe1,0x83,0x78,0x0b,0x53,0x26,0x2d,0x8a,0xbf,0x9a,0x92,0xf7, -0xbf,0x1a,0xa3,0xd7,0xb3,0x27,0x55,0xd8,0xe5,0x72,0xa2,0x1d,0xfd,0xf0,0x19,0x58,0x3b,0x20,0x90,0x17, -0x1c,0x5a,0xf9,0x03,0x42,0x0b,0x61,0x88,0x49,0x18,0xd4,0x1f,0x6c,0x1b,0x97,0x6d,0x30,0x53,0xbc,0x72, -0xe1,0x22,0x4c,0x09,0x40,0xb3,0xaa,0x10,0x03,0x3d,0x05,0xc1,0x08,0x20,0xfa,0x66,0x0e,0xc6,0x07,0x04, -0xb3,0x60,0xb8,0x1a,0xc9,0xd1,0xd7,0x4c,0xd3,0x65,0x06,0x03,0xbf,0x7a,0x27,0x74,0x40,0x9d,0xa1,0x22, -0xd0,0xbb,0x13,0x50,0xfb,0x63,0x82,0x69,0x1e,0x14,0x06,0xac,0xca,0x72,0x58,0xa8,0x27,0x59,0x50,0xce, -0x6d,0xe5,0xce,0xb2,0x67,0x60,0xc6,0x80,0xe2,0x84,0xfe,0x19,0x4f,0x0b,0x93,0x5a,0xb7,0x71,0x1b,0x0a, -0xb7,0x89,0xa5,0x84,0x92,0x22,0x8c,0xe1,0xbe,0x54,0x75,0x47,0x36,0x2c,0x3c,0x62,0x5a,0x24,0x7a,0x4e, -0xe6,0x45,0x02,0xf2,0x7c,0xf7,0xf0,0x78,0xf7,0xfc,0x8d,0x65,0x0d,0x03,0xa7,0x7b,0xde,0xfa,0x5b,0x48, -0x9a,0x73,0x5c,0xcd,0x27,0xc7,0x34,0xbf,0x27,0x48,0x24,0x60,0x30,0xfa,0x7a,0xc9,0x37,0x3b,0x0d,0x0c, -0xef,0xf8,0x39,0x0f,0xe2,0xf5,0x08,0x25,0x94,0x63,0x4f,0x81,0xe2,0x2c,0xff,0x8a,0xa2,0x8d,0x45,0x0c, -0xe8,0x76,0xb8,0x20,0xad,0x9c,0xde,0xf0,0x1a,0x0a,0x5a,0xf6,0x60,0xea,0xba,0xaf,0xa2,0x20,0xae,0xc4, -0x31,0x38,0x3e,0x7d,0xe0,0xfb,0xb1,0xed,0x11,0x71,0x71,0x82,0x92,0x3d,0xb6,0xf7,0x2e,0xba,0xdd,0xdc, -0x1b,0x53,0x95,0x81,0xf8,0x42,0xbd,0x97,0x36,0xbd,0x17,0x09,0x49,0x06,0x3f,0x48,0x5e,0xe7,0x41,0x8a, -0x4d,0xcb,0x52,0x92,0xf5,0xd7,0xa5,0x15,0x5e,0x68,0x71,0x26,0xee,0x77,0xfe,0x21,0xc9,0x45,0xd3,0x3e, -0xc1,0x08,0xc2,0x2b,0x05,0x45,0xe2,0x4e,0x68,0x52,0xd4,0x08,0xd3,0x52,0x09,0xe8,0x62,0xae,0xfd,0x33, -0xe7,0xef,0x18,0x0a,0x72,0x6f,0xa4,0x97,0xba,0xbe,0xb7,0xcc,0xb1,0x9d,0xa4,0x43,0xc2,0x49,0xd9,0xf5, -0x97,0xe8,0x90,0xc8,0xf5,0x9c,0x11,0x65,0xb2,0x45,0x0b,0x9f,0x57,0x27,0xbf,0x37,0x34,0xbf,0x01,0x34, -0x32,0x76,0x87,0x95,0x46,0x07,0xff,0x4d,0x3c,0x5e,0xb0,0x0b,0x25,0x17,0x6f,0xd0,0x47,0x66,0x53,0xf1, -0x13,0xfa,0x41,0xf8,0xb0,0x0c,0x68,0x99,0x65,0xc1,0x78,0xd1,0x31,0x7e,0x89,0xde,0x05,0xfb,0xf5,0x22, -0x15,0xff,0x22,0x1c,0x85,0x6f,0x88,0x8d,0x52,0x87,0x16,0xbe,0x84,0x3a,0xbf,0x3e,0x72,0x64,0x48,0x1f, -0x7d,0x7f,0xcc,0xc0,0x80,0x9a,0xe2,0xb2,0x4f,0x1a,0x85,0x8a,0xde,0x00,0x8a,0x3d,0x89,0xdf,0xa2,0x53, -0x59,0xf2,0xf0,0xfa,0x82,0x44,0x48,0xb2,0x90,0x54,0x59,0xfb,0x9d,0x3d,0x63,0x76,0xc3,0x41,0x5a,0x2c, -0x8c,0xdd,0x7c,0xc0,0x23,0x60,0x98,0x98,0x8a,0x69,0x28,0x62,0xc7,0x18,0xa5,0x07,0xaa,0xab,0x9a,0xe4, -0xb4,0xd1,0xf4,0x30,0x71,0xb5,0x2a,0xe6,0xa0,0x85,0x73,0x82,0x3d,0x67,0x2e,0x07,0x60,0x40,0x75,0xb1, -0x1b,0xc8,0x40,0x60,0xb9,0xc6,0xd0,0xd2,0x30,0x95,0x0c,0xfa,0x19,0x7a,0xa3,0x57,0x5d,0xc1,0x83,0xd3, -0x11,0x83,0xfa,0xc8,0xe0,0xc4,0x67,0x48,0x63,0x0f,0x99,0x05,0xdc,0x21,0xdd,0x3f,0x8c,0x01,0x36,0x5d, -0xcc,0xe2,0xd9,0xab,0x41,0x16,0x61,0x97,0x5f,0x02,0x91,0x82,0x5d,0x76,0xcf,0x83,0x38,0x1e,0xec,0x63, -0x15,0x50,0x2c,0x2c,0x34,0x1a,0xb2,0x86,0x95,0x72,0x27,0x85,0x58,0x62,0x29,0xfc,0xe8,0xa4,0x24,0x25, -0x2e,0x4a,0x17,0x34,0xf1,0x54,0x0a,0x9e,0xb7,0xf7,0x60,0x68,0x38,0x08,0xcb,0x7f,0x64,0x19,0x8c,0xbf, -0x75,0xe3,0xd1,0xab,0x4d,0x40,0x36,0xf1,0x37,0x35,0x15,0x10,0xd3,0x09,0xa9,0x66,0xd5,0xd2,0x73,0x66, -0xc3,0x4b,0xc5,0x2c,0xc5,0xd6,0x16,0x27,0xc5,0xeb,0x73,0xa1,0xe8,0xc1,0x24,0x6e,0x3c,0xc8,0xa2,0x16, -0x0f,0x53,0x35,0x33,0x95,0xd0,0x81,0x81,0x4a,0x39,0xa3,0x4c,0x4c,0xad,0x4f,0x46,0xb6,0x09,0xcc,0xd2, -0xcc,0xb4,0x4f,0xd1,0x8d,0x90,0xb4,0x3b,0xa5,0x3f,0xe3,0x8b,0xdf,0x8f,0x4d,0xd1,0x99,0x9d,0xc6,0x63, -0x53,0x2f,0x9e,0x17,0x8b,0x5d,0xc5,0x67,0xb5,0x16,0x9a,0x14,0xe8,0x1c,0x91,0x22,0x54,0xaf,0x57,0xdf, -0x08,0xec,0x0b,0xf7,0xd7,0xc9,0x81,0x6d,0x5f,0x40,0x8c,0x6a,0x84,0x18,0x87,0x04,0x1d,0x42,0x7a,0xf3, -0x00,0x6e,0x0d,0x59,0x36,0xbd,0xe5,0xec,0x0f,0xc5,0x0d,0x19,0x6d,0x92,0xc3,0xa0,0x2f,0xa7,0x8f,0x1f, -0xf9,0x8c,0x46,0x42,0x13,0x27,0xbc,0xfa,0xec,0x84,0x27,0x34,0xea,0xfa,0xe7,0x26,0x7c,0x66,0x77,0xa3, -0xe9,0x6c,0x2f,0x9e,0x2c,0xb4,0x4d,0xca,0x5f,0x2b,0x35,0x94,0x96,0x47,0x13,0x90,0x15,0xdb,0xea,0xa7, -0xa6,0x93,0x95,0x33,0x1f,0xca,0xb4,0x26,0x0b,0x97,0x2f,0xaa,0x0a,0x0e,0x64,0xa5,0xa1,0xec,0x3e,0x6a, -0x7d,0x96,0xf6,0x2c,0xd7,0xf4,0x33,0xcf,0xde,0x02,0x1b,0x1d,0x82,0xc1,0x81,0x45,0x66,0xf2,0xab,0x25, -0x25,0xeb,0x32,0x44,0xf5,0xda,0x9b,0x0a,0xca,0xcf,0x84,0x4c,0x94,0x96,0x49,0x13,0xf7,0x5e,0xc3,0xb4, -0xe1,0x13,0x57,0x01,0xc0,0xd8,0x1f,0x3f,0x71,0x55,0x16,0xe7,0xac,0xd6,0x4a,0x29,0x13,0x78,0xce,0x35, -0xc4,0x0e,0x5d,0xd7,0x7c,0xb1,0x81,0x8d,0xbb,0x2f,0xb8,0xc7,0xe7,0xbb,0xe9,0xc8,0x05,0xd9,0x6e,0xf7, -0x30,0xf7,0xa6,0x44,0x81,0x71,0xa0,0xcf,0xd0,0x9c,0xd6,0x9e,0x23,0xca,0xef,0xcd,0x0c,0x86,0x53,0xf6, -0xc0,0x61,0x21,0xce,0xc4,0x31,0xac,0x97,0xcb,0xff,0x6a,0x78,0xc9,0xed,0x9d,0x26,0x89,0xd1,0xda,0x46, -0x6c,0x2a,0x7f,0x36,0x6a,0x37,0x08,0x66,0xe2,0xef,0x38,0xe0,0x0c,0xfb,0xc4,0xf1,0xc0,0xca,0xa5,0x87, -0x1f,0xb8,0x67,0xcc,0x5c,0x62,0xff,0xb8,0x15,0x5a,0xb5,0x18,0xab,0x33,0x3c,0x9e,0xb2,0x1d,0xbb,0x92, -0x66,0x36,0x9b,0x15,0x86,0x4e,0xbf,0x00,0xf2,0xae,0x28,0x8d,0xe3,0x16,0x46,0xde,0x38,0xf9,0xb6,0x9b, -0xe7,0x5a,0x89,0x0b,0x6a,0x00,0x50,0x36,0xa6,0x3d,0x21,0x16,0xd0,0x4e,0xa1,0xc7,0xef,0x34,0xc5,0x34, -0xac,0xe9,0xa3,0x02,0x2c,0xa2,0xf4,0xe6,0x88,0x5d,0xbc,0x84,0x94,0xde,0x5f,0x33,0x71,0xc8,0x87,0x7f, -0xf8,0xb5,0xdd,0xbf,0xfa,0xa6,0x81,0x96,0x77,0x5e,0x18,0xd5,0xe2,0x24,0x27,0xee,0x02,0x36,0xf0,0x01, -0x37,0x3a,0xf0,0x81,0xbe,0x51,0x8a,0x60,0x8f,0x17,0xad,0x29,0x98,0x8a,0x15,0x7a,0x46,0xc5,0x7f,0xfc, -0xe9,0xf7,0xf9,0x58,0x2b,0x6d,0x28,0x79,0x19,0x9d,0x79,0xcb,0xb6,0x81,0x23,0xf2,0x60,0x7a,0xd2,0x06, -0xae,0xa7,0xa3,0x44,0x42,0x50,0xde,0x50,0x68,0x74,0xf0,0x78,0xdb,0x39,0x9e,0x9e,0xf9,0x55,0x4e,0xa4, -0x8d,0x5f,0xa0,0xd3,0xd7,0xff,0x38,0x33,0x3a,0xf4,0xa8,0x1e,0x82,0x13,0x9c,0xc6,0x63,0x9e,0x50,0x41, -0x69,0x61,0x9e,0x87,0x61,0x22,0xd1,0x5d,0xba,0xbd,0xec,0x5b,0xee,0xba,0xce,0x4e,0x3d,0xf1,0xbd,0x02, -0xb0,0xb8,0x99,0x0f,0xf5,0x83,0x9f,0xe5,0x35,0x88,0xf3,0x24,0x2b,0x67,0x39,0x73,0x05,0x4b,0x75,0xca, -0x2c,0x52,0x36,0x19,0x3f,0xd1,0x4b,0x39,0x3d,0xef,0xbb,0x15,0xc8,0x08,0x08,0x20,0x65,0x00,0x9a,0x7c, -0x5c,0x7c,0x87,0xc7,0x94,0x02,0x1f,0xa3,0x8b,0x69,0xee,0x9a,0x52,0xa2,0x76,0xa7,0x52,0xc6,0x84,0x98, -0xe0,0xf0,0x12,0x0d,0x76,0xe3,0x3c,0xe9,0xf4,0xf0,0x88,0x14,0x73,0x2f,0x0c,0x54,0x98,0x34,0xf1,0x7b, -0x30,0x60,0xa7,0x27,0x71,0x61,0xd1,0x5d,0x77,0x97,0xf5,0x57,0x51,0xe4,0xa3,0x4e,0xae,0xd2,0xe7,0x97, -0x5f,0xd0,0x73,0x55,0x05,0xd0,0x74,0x74,0x16,0xca,0xbb,0x20,0xc6,0xcd,0xbb,0x6e,0xef,0xd0,0x7d,0x40, -0x87,0x1d,0x6f,0xa4,0x07,0x54,0x73,0x74,0xdf,0xc5,0x3f,0x90,0x46,0x33,0xe7,0x68,0xd2,0x95,0x94,0x3b, -0x2e,0x9d,0x2d,0x2d,0x51,0x1c,0x84,0x4e,0xe6,0x27,0xde,0x2e,0x97,0x82,0x25,0xfa,0x36,0x8a,0x23,0x2f, -0x38,0x8c,0x21,0x5f,0x96,0x4b,0xf1,0xa2,0x32,0x23,0x1d,0x31,0xc0,0x37,0x04,0x18,0x0e,0x2c,0x25,0xf3, -0xae,0xd3,0xd9,0xdf,0xdf,0xda,0xe2,0xf6,0x30,0x22,0x2c,0xd3,0xe9,0x74,0xd4,0xfd,0xfd,0x7d,0x75,0x0b, -0x8a,0x19,0xa0,0xfc,0x42,0x80,0x5f,0x85,0x37,0xc8,0x20,0x4d,0x06,0x9a,0xbe,0xc7,0xd7,0xfe,0x21,0x15, -0x06,0x4c,0x70,0xf8,0xb7,0x52,0xab,0xbd,0x09,0x24,0x3c,0x35,0x2e,0xce,0x61,0x9e,0xb4,0x89,0x41,0x83, -0x93,0x0a,0x42,0x62,0x12,0x29,0xff,0x07,0x13,0x2c,0xb3,0x21,0x90,0x72,0x89,0x5c,0x22,0xea,0x26,0xb0, -0x09,0x75,0x8f,0x59,0xa0,0x62,0x55,0xa4,0xeb,0x5d,0x6d,0xb3,0xb3,0x38,0xfc,0x68,0xf3,0xef,0xce,0x70, -0x6c,0x38,0x44,0x4f,0x9e,0x1d,0x7e,0x25,0x86,0x38,0xf4,0x24,0x11,0x9f,0x16,0x3d,0x87,0xed,0x10,0x5d, -0x1e,0x39,0xa5,0x5f,0x71,0xd2,0x55,0x74,0x1a,0x8d,0xa6,0xf0,0x0c,0x37,0x5c,0x9f,0xe1,0x25,0x49,0xf8, -0x09,0xa6,0x19,0x5a,0x4c,0x53,0x0f,0x77,0x9d,0x2e,0x26,0x36,0xf7,0xf8,0xe9,0x11,0x27,0x71,0xfa,0x92, -0xa7,0xce,0x88,0x14,0x2b,0xb6,0x3d,0x51,0xe2,0xe2,0xe2,0x84,0xb2,0x2d,0xdf,0xbf,0xf4,0x73,0xe3,0xb2, -0x3a,0x99,0xf0,0x03,0x90,0x36,0x3f,0x10,0x8a,0x97,0xdf,0xe4,0x70,0xbf,0xa9,0x21,0x65,0xbb,0xb0,0x5c, -0x99,0xe4,0xdc,0x12,0xff,0x6e,0x20,0xff,0x5a,0x67,0xf1,0x66,0xe4,0xdf,0xd7,0x10,0x7b,0x85,0xd7,0x2e, -0xc5,0x0a,0xe9,0xed,0x54,0x7e,0xa9,0x1c,0x44,0x02,0xd6,0xc8,0x8a,0x5a,0x9d,0x6e,0xb7,0xed,0x57,0xcb, -0x05,0xad,0xa7,0xfc,0xb6,0x1b,0x3f,0x15,0x07,0xa8,0xc3,0x0f,0x96,0x4a,0xb5,0x06,0xc1,0x45,0x34,0x49, -0x93,0x99,0xd0,0x53,0xf1,0xee,0x14,0x0f,0x58,0xbf,0x22,0x11,0xe6,0xe5,0x51,0x13,0x34,0x40,0x3f,0x75, -0x4f,0x8e,0x85,0x00,0x7e,0x55,0xe8,0xa4,0xfa,0x52,0xdb,0xf3,0x93,0x6b,0x5b,0x29,0xc6,0xe7,0x4b,0x40, -0x7d,0x9d,0xaa,0xc4,0x4d,0x50,0x1e,0x7a,0x72,0x95,0x2c,0x79,0xec,0x93,0x49,0xe8,0x58,0x3d,0x63,0xfd, -0x9c,0xcf,0x99,0x86,0xd5,0x37,0xa7,0x3a,0xdb,0xed,0xd2,0x42,0xc8,0x00,0xfd,0x02,0xf8,0x0e,0x44,0x01, -0x12,0x14,0x5a,0x8f,0x27,0x94,0x46,0x82,0x9d,0x78,0xa2,0x1e,0xa8,0x9a,0xa9,0xa5,0x93,0xf0,0x5d,0xe3, -0xa1,0x35,0x87,0x17,0xa0,0x04,0x64,0xa6,0xcb,0x89,0xae,0x86,0x23,0x01,0xac,0x80,0xe8,0x7e,0x4a,0xa6, -0x3c,0x43,0x80,0xf6,0xcb,0x8e,0xe0,0x97,0xf1,0xc2,0x04,0x4c,0x2f,0x90,0x62,0xa2,0xfe,0x3c,0xfb,0xe2, -0x44,0xd0,0x98,0x80,0xbd,0x88,0x73,0xc1,0x94,0x02,0x21,0xf5,0xf8,0x7c,0xe8,0x68,0xdd,0x69,0xcf,0xed, -0x3b,0x46,0x8f,0x26,0x6b,0x8a,0x33,0xb6,0x7c,0x60,0x1d,0xf5,0x1b,0x2a,0x5d,0xd6,0x8c,0x82,0xe8,0xfe, -0x76,0x52,0x24,0xbb,0x3e,0x36,0x25,0x50,0x49,0xaf,0x88,0x8d,0xc5,0x29,0xa9,0x7e,0xc3,0x4b,0x72,0xb2, -0xfc,0x76,0x36,0x05,0x53,0x3d,0x94,0x53,0xc7,0xc6,0xb8,0x80,0x99,0xe3,0x56,0x36,0xcf,0x6b,0xc3,0xeb, -0x44,0x22,0x57,0xc0,0xc0,0x24,0xee,0xd0,0x4f,0x94,0xb7,0x43,0x69,0xca,0x04,0x13,0xd7,0xcc,0x50,0xa7, -0xa7,0xb8,0x51,0x6e,0xd3,0x5a,0xf4,0x0c,0xb3,0x41,0x2f,0x0c,0xf9,0xc3,0x39,0x96,0xf4,0xf6,0x1f,0xb6, -0x73,0xf6,0xae,0xf4,0x2b,0xf6,0x28,0x5e,0xf5,0x43,0xdb,0x97,0x9f,0x37,0x48,0x57,0xd3,0x73,0xa8,0x7f, -0x09,0xe0,0xf2,0x6f,0x01,0x5c,0x79,0x01,0xc0,0xe9,0xdb,0xe7,0xbf,0x04,0x70,0xe5,0xb7,0x00,0xae,0xbe, -0x00,0xe0,0x37,0x88,0x38,0x52,0xf6,0x06,0xdb,0x96,0x6a,0xfa,0x57,0x3b,0xfe,0xe9,0xb5,0xd8,0x4e,0x54, -0x30,0xa9,0x13,0x3a,0x44,0x34,0x18,0x42,0x83,0x1f,0x79,0xcc,0xc1,0x65,0xb7,0xcc,0x84,0xce,0x6c,0xae, -0xae,0x8a,0x0b,0x6c,0xff,0x95,0x87,0x25,0x70,0x9b,0x91,0xc9,0xf7,0x2e,0xb7,0x24,0xe8,0xca,0xbd,0x38, -0xdf,0x96,0xaf,0xb7,0x7b,0xc3,0x64,0xbb,0x9d,0xee,0x5b,0xef,0x23,0x00,0xfa,0xa1,0xd3,0x48,0xd8,0xe5, -0x17,0xe4,0x69,0x70,0x15,0x73,0x9a,0x50,0x0d,0xae,0x68,0x8e,0x49,0x56,0xe6,0x55,0xf8,0xa1,0x26,0x91, -0x12,0xb2,0xc3,0xfb,0xf4,0xc3,0x17,0xaf,0x3a,0xb5,0xfc,0x82,0x43,0xc9,0xbf,0x44,0x02,0x0e,0xd4,0x1b, -0xd3,0x41,0xef,0x7f,0xff,0xa3,0xdb,0x39,0x2d,0x70,0xa7,0xf1,0x62,0xe5,0x29,0x35,0x44,0x39,0x7b,0xfe, -0xe6,0x9a,0x0e,0xad,0x63,0x98,0x40,0xf7,0xce,0x98,0x24,0xae,0xe2,0xe0,0xa6,0xa8,0xd0,0xe4,0xfe,0x95, -0x07,0x69,0xa4,0xa5,0x0b,0x50,0x07,0x36,0x0b,0x75,0xa2,0xfc,0x83,0x6c,0xed,0x9d,0x2f,0x22,0xb4,0xe6, -0xd2,0x0b,0x8f,0xc4,0x3d,0x2b,0xee,0xdb,0x50,0xc5,0xe7,0xf0,0xf6,0xf1,0xaf,0x07,0x82,0x00,0xf3,0xb4, -0x6d,0xdb,0x4a,0x4b,0xc4,0x59,0x80,0xe9,0xd7,0x83,0x7a,0x72,0x71,0xfe,0xfb,0xb0,0x9e,0x4c,0x23,0x3b, -0x68,0x41,0x7a,0xb7,0x7f,0x55,0x9a,0x04,0x7f,0x40,0x7f,0xbe,0x96,0xbb,0xec,0xba,0x79,0x85,0x1e,0x02, -0xc0,0xc6,0x53,0x3c,0x33,0xe1,0xbe,0x7e,0xad,0x07,0xe2,0x1b,0x69,0x1d,0xbd,0x1f,0xcb,0xb2,0x79,0x24, -0x95,0xda,0xa5,0x9c,0x37,0x34,0x4c,0x60,0x1c,0x83,0x7f,0x09,0xc6,0x6e,0xf2,0xf9,0x76,0x21,0x0c,0x3b, -0xc9,0x77,0x52,0x8b,0xd7,0x47,0xf1,0xbb,0xa6,0x7f,0x41,0xf2,0xb2,0x1b,0xec,0x53,0x84,0x6e,0x70,0x4b, -0xfd,0x4b,0x85,0x6e,0xdb,0x1a,0x98,0xd3,0xc7,0x9d,0x2d,0x21,0x74,0x15,0xb6,0x1d,0x46,0x2f,0x30,0xc3, -0xdd,0x24,0x0a,0xa0,0x02,0x6e,0xbe,0x37,0x97,0x31,0xe5,0x37,0x0b,0xba,0xfc,0x9f,0xdd,0x63,0x17,0x00, -0xbc,0xb1,0x5c,0x06,0xec,0x26,0xc8,0xe5,0xd5,0x37,0x93,0xcb,0x78,0x5f,0xe3,0xaf,0x2c,0x24,0x80,0xeb, -0x80,0xde,0x6c,0x99,0xbc,0xe2,0xdf,0xc2,0xc0,0x7e,0xd5,0x16,0x79,0x18,0xb4,0xf8,0x0e,0xf9,0xdb,0x9a, -0xd2,0x3b,0x60,0xfa,0xf5,0xe8,0x31,0x9d,0x5f,0x02,0x4f,0x34,0x4f,0x05,0xf1,0x0d,0x8c,0x67,0xdc,0x6d, -0x4f,0xb8,0x88,0xf3,0xa5,0x20,0x8a,0xe6,0xa9,0x20,0xae,0xfe,0xa1,0x0d,0xe9,0x57,0x6f,0xbe,0x47,0x28, -0x9f,0xba,0xf7,0x2e,0xc1,0x5e,0x5b,0x0c,0xfb,0x2f,0x08,0xc1,0xe0,0xb3,0x25,0x29,0x82,0x90,0x7d,0x96, -0x44,0xd9,0x3e,0x39,0xde,0x6b,0xef,0x5f,0x44,0xce,0x3a,0xca,0xb9,0x48,0x3a,0xa6,0x8d,0x1b,0x3d,0x07, -0x77,0xcf,0x64,0x47,0x9d,0x8f,0xf0,0x47,0x8c,0xd0,0x17,0x9e,0x11,0xd3,0x74,0x76,0x9a,0xe8,0x41,0x33, -0x7f,0x29,0x5d,0xc0,0xb5,0x5c,0xec,0x24,0x96,0x2e,0xb0,0x96,0xf9,0xb0,0x16,0xd8,0x35,0x29,0x89,0x02, -0x20,0xf1,0xca,0xa5,0x67,0x6b,0xd5,0xa0,0x56,0xed,0xb9,0x5a,0x68,0xd5,0x56,0x9f,0xed,0x6b,0x0d,0x47, -0xe4,0x01,0xdd,0xf4,0x9e,0xa0,0x52,0x4d,0x44,0x7d,0xff,0x66,0x37,0x0e,0x76,0x19,0x69,0x50,0x73,0x0a, -0xb2,0x29,0x3d,0xe2,0xcd,0x08,0xbd,0x2d,0x8e,0x7e,0xae,0x8a,0xa5,0x0c,0xba,0xc4,0x8f,0xb2,0xf9,0x87, -0x6f,0xe8,0x29,0x46,0xd0,0xbf,0x78,0x59,0x9f,0xbf,0xbb,0xcb,0x62,0xd2,0x22,0xcd,0x90,0x7d,0x83,0x10, -0x2b,0xa2,0xd1,0x34,0x1e,0x03,0x7b,0x41,0x5d,0xb6,0xbf,0x60,0xb8,0x8a,0x4f,0xd2,0xb7,0x3b,0xa3,0x88, -0xd1,0x77,0x1a,0x6b,0xff,0x05,0xd7,0x41,0x62,0xc1,0x49,0xd2,0xd9,0xbf,0x44,0xc7,0xa1,0xec,0xdf,0x36, -0x2b,0x3c,0x88,0xbf,0xc7,0xe1,0x6d,0x89,0xb4,0xfc,0x7a,0x56,0x7b,0xe0,0xd3,0x94,0x1d,0x9c,0xa2,0xa4, -0xe3,0xd4,0x61,0x07,0x21,0x17,0x11,0x21,0x76,0xda,0xc4,0xdf,0x46,0x79,0x71,0xb0,0x46,0xda,0x79,0x99, -0x82,0x59,0xe9,0x46,0x45,0x04,0x3f,0x38,0x32,0x9e,0x5c,0xe0,0xdb,0x48,0x46,0xed,0xb3,0x44,0x8c,0x25, -0x18,0x6d,0x13,0xd3,0x35,0xa6,0xae,0x92,0x5d,0xd6,0xc9,0x70,0x73,0x3b,0xb7,0x20,0xc3,0x68,0x4f,0x1b, -0x39,0xc4,0x1a,0x11,0xc3,0xe3,0xb5,0xf7,0x72,0x2f,0x4f,0x1d,0x7a,0x5b,0xcc,0x24,0x5c,0xe4,0x21,0xb3, -0x27,0x60,0x67,0xdb,0xaf,0xf1,0x16,0xd7,0x25,0xe7,0xe9,0x35,0xc9,0x8c,0x87,0x4b,0x85,0x72,0x70,0x63, -0x72,0x08,0xff,0xf5,0x17,0x6c,0xcf,0xff,0xd1,0xf3,0x3b,0x89,0x18,0x0a,0x44,0x09,0xdb,0xa7,0xe7,0x21, -0xea,0x31,0xd1,0xdc,0xa9,0xe3,0x4b,0x9a,0xd9,0xc8,0xe8,0x8f,0x60,0x5a,0x73,0xb6,0x6d,0xa1,0xf5,0xfb, -0x53,0xaa,0x3b,0x75,0x76,0xdd,0x30,0xf5,0x99,0xf1,0x33,0x35,0xa8,0x3b,0xa9,0xe0,0x62,0xcd,0x70,0x9f, -0x18,0x1a,0x58,0x64,0x48,0x3f,0x7b,0x1d,0x96,0x51,0x8b,0xae,0x9d,0x1b,0x99,0x33,0xf1,0x93,0x8c,0xf1, -0xcb,0x18,0xbb,0xa0,0x60,0x87,0x78,0x1d,0x27,0xb0,0xb5,0xed,0xbc,0xfc,0x0a,0x3a,0xd6,0xfa,0x65,0x2c, -0x74,0x69,0x9b,0x1e,0x2c,0xe7,0x5f,0xb1,0x89,0x26,0x33,0x87,0xb7,0x4e,0x0a,0xda,0xd6,0x65,0x3e,0xa8, -0xbd,0xe4,0x42,0xf5,0xd7,0x53,0xf7,0x48,0x33,0xc0,0x79,0x7d,0x60,0x40,0xf8,0xd9,0xd4,0xee,0xdc,0xc5, -0x6f,0x93,0xe1,0x0e,0xe0,0xe5,0x73,0x47,0x5c,0xa2,0x57,0x2b,0x9a,0xb3,0x97,0x22,0x6e,0xf7,0x71,0xc2, -0x8e,0x79,0xf1,0xcf,0x7e,0xbc,0x06,0x83,0x0a,0xa0,0x4e,0xb4,0x97,0xb0,0x29,0x8a,0xb6,0x9f,0xc7,0x67, -0x25,0x92,0xd9,0x59,0xfa,0x23,0xf8,0x6d,0x5b,0x4a,0x0b,0xd7,0x0f,0xc8,0xc2,0x56,0xce,0x3f,0x1c,0xab, -0xf9,0x1f,0x14,0xd6,0x68,0x2b,0xbc,0x10,0xdb,0x70,0x91,0xd7,0x15,0xba,0x8d,0x67,0x1a,0x77,0xa0,0x1e, -0x94,0xde,0xd4,0xec,0x49,0x9b,0xd2,0x54,0xcb,0x63,0xb8,0xc1,0xb7,0x14,0xe8,0x1e,0xdf,0xcc,0xc6,0xf4, -0x98,0x07,0xe9,0x10,0xae,0xaa,0x18,0x05,0x52,0x50,0xd8,0x5e,0x6c,0x51,0x50,0x37,0x92,0x85,0x82,0xb7, -0xf0,0x68,0x7e,0xd2,0x09,0xcc,0x05,0x77,0x09,0xe9,0x07,0xbc,0x69,0xd2,0xc8,0xc0,0xe6,0x47,0xd6,0x67, -0x34,0xb3,0xc6,0x21,0xae,0x38,0xc4,0x19,0x5c,0x19,0xfe,0xe7,0x39,0xe3,0x17,0xd6,0xd6,0x33,0x9c,0x71, -0xf9,0x3c,0x67,0x44,0x93,0x9c,0xff,0x18,0x67,0xe0,0xec,0x80,0x31,0x60,0x89,0x29,0xbb,0xf4,0x93,0xe1, -0x74,0xf1,0x51,0xc3,0xc1,0x06,0x0d,0x01,0x26,0x61,0x6b,0xdb,0x5f,0x9b,0xfe,0xb6,0xdf,0x08,0x08,0x4d, -0x61,0xc3,0x64,0x19,0x90,0x9e,0x86,0x69,0x78,0x73,0x55,0xa1,0x69,0x37,0x80,0x6c,0xbc,0x3c,0x93,0x9d, -0x8d,0xfd,0x7d,0x7a,0xfd,0x8a,0x38,0xf4,0x69,0x77,0x8a,0xac,0xf3,0x86,0x94,0x4b,0x4c,0xac,0x0c,0x53, -0x2e,0x9a,0xad,0xfd,0xc7,0x28,0x77,0xa5,0x79,0x48,0xb9,0x2b,0xa0,0xdc,0x76,0xd8,0x23,0x64,0xae,0xa0, -0x74,0xa7,0x77,0xca,0x12,0xcf,0x4a,0x6b,0x9c,0xdd,0x4b,0xc2,0xbe,0x1a,0x4f,0xbf,0xd6,0x4d,0xdd,0x02, -0x18,0x40,0xb0,0x01,0x5b,0x85,0x9c,0xc2,0x9a,0x44,0xe3,0xdf,0xa5,0xe8,0xcb,0x23,0x69,0x1d,0x4c,0xc0, -0xf3,0xdd,0xdf,0xb7,0xbf,0xec,0x0c,0x08,0x4d,0x87,0xd8,0x0e,0x46,0x08,0x91,0x36,0x3d,0xa3,0xf9,0x7f, -0xd2,0x18,0x3a,0xb2,0x1f,0xf8,0x97,0x17,0x78,0x52,0x9d,0x87,0xf7,0x95,0x51,0xf2,0x4d,0xe8,0x79,0x94, -0x0c,0xfb,0xfa,0x0c,0xbd,0x72,0x0b,0xcc,0x7c,0xba,0xf1,0xc7,0x2c,0x9c,0xb9,0x8c,0x3c,0x71,0x00,0xfe, -0x77,0x77,0xd6,0xd8,0xf7,0x42,0x53,0xc2,0x1a,0xc1,0x37,0x41,0xc5,0xad,0xbf,0xb6,0x65,0x0f,0x06,0xca, -0x6a,0xb5,0xaa,0x74,0xf6,0x94,0x2d,0xc7,0xd0,0x41,0xae,0x6c,0x87,0xee,0x3c,0xc5,0x3c,0x2c,0x3c,0x60, -0x6d,0x63,0xd2,0xbf,0x63,0xf1,0xcb,0x7e,0xfa,0x78,0x07,0x10,0xfb,0x80,0x84,0x48,0x14,0x39,0xdc,0x6d, -0x75,0x8e,0x23,0x9f,0xa2,0xe7,0xfd,0xc3,0xb8,0xac,0x6b,0xee,0xb8,0x92,0x09,0x7d,0x6d,0x71,0x14,0x69, -0xe2,0x3b,0x0f,0x3c,0x63,0x8a,0x9d,0xbe,0x65,0x3d,0x84,0x9b,0xd2,0x46,0xfc,0x33,0x14,0xd8,0x8d,0xff, -0xe1,0x7a,0x1f,0x26,0x7e,0xb1,0xac,0x8b,0x77,0xcf,0x4e,0x27,0x7e,0x12,0x24,0x0f,0xcb,0x48,0x4d,0x83, -0x2f,0x6d,0xd0,0x76,0xba,0x4d,0x5c,0x9a,0x58,0xca,0xaf,0x0a,0x34,0x3c,0x9a,0x32,0x89,0x25,0x3d,0x42, -0x21,0xb5,0x41,0x69,0xe3,0x2d,0xfb,0x88,0x05,0xf0,0xaa,0x69,0x0e,0x3f,0xbb,0xb2,0xbf,0x20,0x90,0x74, -0x64,0xeb,0xf8,0x45,0x19,0x5c,0xed,0xe0,0xde,0x79,0x01,0x58,0x6e,0xf0,0xf9,0x8b,0x2c,0x5e,0x33,0xc0, -0xcb,0xf0,0x76,0x03,0x30,0x6b,0xcb,0x75,0xe9,0xde,0x22,0x05,0x13,0x76,0x72,0x62,0x62,0x56,0x04,0xc9, -0xdd,0xd6,0xe5,0xae,0x9c,0x80,0xa3,0xb0,0x93,0xb4,0xec,0x8e,0x78,0x4b,0x9e,0xea,0x18,0x90,0xe8,0xcc, -0x85,0x81,0x41,0xe5,0x0f,0xb4,0x32,0xe9,0x75,0x07,0xac,0x06,0x88,0x0e,0x37,0xd8,0xbc,0xa2,0x58,0x08, -0xb2,0x55,0x39,0x0f,0xd3,0xcb,0xe9,0x19,0xe1,0x7d,0x54,0xf9,0xc9,0x44,0x50,0x87,0x13,0x8e,0x06,0xc2, -0xec,0xc9,0x1c,0xcf,0xbe,0x30,0xe4,0x71,0xf3,0x1f,0x2f,0xb3,0x67,0x8b,0x1c,0x56,0xb6,0x2a,0xcf,0x08, -0x67,0x22,0x08,0x6e,0x6a,0xfc,0x52,0x63,0x79,0x42,0xd2,0x9d,0x90,0xf8,0xff,0x1d,0x82,0xc1,0x3f,0x7a, -0xeb,0x53,0xc0,0x7c,0xe2,0x9b,0x39,0x02,0x3d,0x7b,0x27,0x9d,0x7d,0xbc,0x3d,0x41,0x20,0xc8,0xff,0x7e, -0xce,0xeb,0x4e,0x4b,0xc2,0x22,0x3a,0xb6,0x5f,0xb0,0xd1,0xb2,0xe0,0xbb,0xe7,0xbc,0x0b,0xf4,0x95,0x4c, -0xfc,0xf8,0xa7,0x18,0xd3,0x13,0x05,0xc1,0xe6,0x14,0x43,0xf8,0xbb,0xc8,0x17,0xce,0xdf,0x66,0x1b,0xba, -0x2b,0xa8,0x19,0x11,0xce,0xcf,0x1f,0x37,0x89,0x64,0x8d,0x80,0x27,0x6a,0xd2,0xa3,0xa7,0xd4,0x01,0x15, -0xf7,0x67,0x0f,0x7a,0x48,0x0b,0x96,0x5c,0x91,0xc7,0x69,0x97,0xf9,0x6f,0x96,0xa1,0x96,0xf6,0xd1,0x27, -0xe8,0x3d,0xed,0x80,0x72,0xfa,0x81,0x54,0xbe,0x83,0xcc,0x1a,0x46,0x3e,0xe1,0x3b,0xe8,0xe5,0x29,0x93, -0x66,0x84,0x14,0x7a,0xfe,0x88,0xf4,0xdb,0x43,0x80,0x19,0xcc,0x19,0xbe,0x42,0xff,0x15,0xe3,0x03,0x33, -0x0e,0xf1,0xd2,0x11,0xb1,0x08,0x5e,0x7a,0x8e,0xfe,0xf5,0xdc,0x84,0x9f,0x6b,0xf9,0x97,0xb0,0x53,0xb2, -0xf9,0xf6,0xbf,0xec,0xf4,0xaf,0x62,0xa7,0xb0,0xcc,0xe3,0x47,0xae,0x17,0xc9,0xbc,0x5f,0x8e,0x27,0x8b, -0x24,0xca,0x6e,0x17,0x3f,0xfc,0x9b,0x1a,0x4f,0xae,0xe5,0xd7,0xe4,0xd4,0xb1,0x7c,0x35,0x1a,0x51,0x76, -0x0d,0xfd,0xd9,0x54,0x82,0xc4,0xbc,0x15,0x1e,0xa0,0x4c,0x74,0x33,0x4a,0x11,0x2f,0x43,0x06,0x36,0x43, -0x6f,0x41,0x32,0x68,0x94,0xfe,0x15,0x3b,0x70,0x48,0xd3,0xb5,0x10,0x12,0x68,0x30,0xfb,0x95,0xc7,0xf6, -0xc1,0x04,0x20,0xe2,0xdc,0xbe,0xe8,0x0c,0x44,0x72,0xa1,0x50,0x88,0xd2,0xf3,0x05,0x44,0x50,0xb0,0xb7, -0x5f,0xdb,0xf2,0x63,0x4d,0x85,0x61,0xaf,0xe1,0xf9,0xd8,0xf4,0x6b,0x07,0x7d,0x3a,0xf8,0x28,0x0f,0x61, -0x3a,0x19,0x8b,0x2f,0x87,0x1f,0xbf,0x30,0x69,0xf4,0x15,0xcc,0x97,0xff,0xc5,0x09,0x04,0x79,0x4b,0xa9, -0x2c,0x14,0xe1,0x96,0x72,0xed,0x45,0x93,0x78,0xd6,0x3d,0xe1,0x53,0x78,0x95,0x8f,0xc2,0xdb,0xb0,0xc4, -0x0c,0x96,0x89,0x81,0x91,0x83,0x9d,0xe3,0x2e,0xc6,0x53,0x6d,0xcf,0xe0,0xce,0xdb,0x2b,0xd9,0x60,0x1f, -0x16,0xf4,0x4c,0x9b,0xff,0x0e,0x1e,0x87,0xb3,0xff,0x03,0xf1,0x88,0xc9,0x3f,0x33,0xf9,0xf3,0x35,0x6e, -0xc0,0x4f,0xaf,0x44,0xa1,0x10,0x13,0x47,0x9a,0x7b,0xf7,0xcb,0x48,0x1c,0x43,0xe3,0x97,0xa2,0x11,0x0f, -0x2d,0x89,0xff,0x97,0xfe,0x46,0x38,0xbd,0x70,0x99,0x6f,0x14,0x82,0x8f,0x72,0x69,0x11,0xf4,0x93,0xb8, -0xbb,0xe4,0xd5,0xf8,0x45,0x16,0xff,0x0d,0xf6,0xd4,0x2d,0xf7,0xa5,0x88,0xad,0x17,0xe8,0x9f,0xbf,0x11, -0x4a,0xc5,0x11,0xab,0x1d,0x9b,0x7e,0xa0,0xee,0x18,0x5d,0x3c,0x9e,0x4e,0xde,0x3e,0xa5,0x57,0xe2,0xbb, -0x64,0x31,0x1f,0xbf,0x12,0xba,0x57,0x6a,0x26,0x1d,0x4f,0x55,0x70,0xfe,0xe7,0xd4,0x62,0x0e,0x5e,0xfc, -0x62,0x99,0x24,0xef,0x0a,0x53,0xe5,0x5e,0x6b,0x67,0xbc,0xda,0xce,0x7d,0x17,0x3a,0xf3,0x66,0xc8,0x5f, -0x30,0x7f,0xa3,0x48,0x17,0x6f,0xc5,0xbe,0x43,0xc4,0xae,0x9f,0x49,0xe9,0x21,0x96,0xbf,0x9e,0x8a,0x16, -0x16,0xbe,0x79,0xad,0xe3,0x99,0x30,0x4b,0x25,0xbb,0x7f,0xda,0x3e,0x09,0xbd,0x1d,0x4e,0x0c,0xdb,0x7f, -0x9f,0x7b,0x2b,0x27,0x75,0x0b,0x4f,0x03,0x87,0xbe,0xd2,0xc4,0xa6,0xf5,0x6c,0xb6,0x8a,0xb4,0x71,0x46, -0xa7,0x8e,0x1d,0x25,0xed,0x3e,0x27,0x7d,0x66,0x32,0xb6,0xef,0xfc,0xec,0xf7,0x2a,0xc1,0xfe,0xea,0xd2, -0xc3,0x52,0xae,0xd2,0x23,0x03,0x7a,0x55,0x59,0xea,0x57,0x97,0xce,0x6d,0x7b,0x48,0x03,0x4d,0xe1,0x7a, -0x2f,0xb8,0xf9,0xe2,0xe5,0x68,0x3b,0x9d,0x9a,0x2e,0x79,0x13,0xbc,0xd1,0x9e,0x92,0x10,0xb7,0x43,0xbf, -0xef,0x3a,0xc1,0xd7,0x0b,0x30,0x77,0x6c,0x3b,0x63,0x2a,0xbf,0x17,0x20,0xb8,0x22,0x57,0x3b,0xfe,0xa3, -0x18,0xa1,0x87,0xa4,0xb2,0xee,0xaf,0x5f,0xb7,0x28,0x61,0x86,0x5e,0xcf,0xfb,0xa2,0xe4,0x93,0x84,0x8d, -0xfb,0xea,0x5a,0xe9,0xd9,0xcc,0xcf,0x84,0x2b,0x2a,0x5e,0x35,0x65,0x7a,0x68,0x75,0xe8,0xd8,0x78,0x6b, -0xdf,0x2f,0x9e,0x7b,0x0c,0xce,0x39,0xee,0x63,0x3f,0x49,0xd3,0x95,0x75,0x99,0x10,0x44,0x09,0xea,0xf0, -0x7f,0x6c,0xae,0xf4,0xab,0x61,0xbf,0xc1,0xf5,0xfe,0x64,0xdb,0xd6,0x43,0x12,0xdf,0x77,0xb5,0xf4,0x4f, -0xdf,0x96,0x71,0xbf,0x07,0x4f,0xee,0xa5,0xaf,0xeb,0x04,0xa9,0xdc,0xd6,0x1f,0xff,0x88,0x5f,0xcc,0x84, -0xf8,0xdb,0x1c,0xce,0x50,0x74,0x9e,0x84,0x0e,0xc0,0x4a,0x29,0xf8,0x41,0x51,0x32,0xdb,0x27,0x72,0xc7, -0x22,0x35,0xe5,0xdf,0x2c,0xfd,0xa7,0x90,0xe2,0xa7,0xca,0xbf,0x11,0x5e,0xfa,0x74,0x27,0x4e,0x42,0x89, -0x3f,0xc0,0x2f,0xe1,0xe4,0x39,0x60,0xd8,0x59,0x13,0x31,0xea,0x22,0x4c,0xd2,0x43,0xf3,0x9d,0xfd,0xad, -0x3f,0x82,0x45,0xfa,0xd1,0x95,0xd7,0x5d,0x50,0x44,0x83,0x75,0xb3,0xfe,0x24,0x0f,0x1c,0x63,0x4f,0x3d, -0x30,0x04,0x4d,0xbb,0x7f,0x27,0x10,0xc7,0xee,0x09,0x48,0xbe,0x3f,0xf3,0x37,0xd3,0x0d,0xb7,0xfc,0x0b, -0x1d,0x22,0x00,0x33,0xf2,0x38,0x78,0xd7,0x5f,0xe4,0x78,0x11,0x38,0x19,0x3e,0xba,0x5c,0xd3,0xc0,0x73, -0xcf,0x91,0xd9,0x20,0x86,0x83,0x9b,0x22,0x32,0x1f,0x94,0x90,0x2d,0xc4,0xdb,0x04,0x15,0xe2,0x3b,0x89, -0xdc,0x58,0x4c,0x23,0xdc,0x41,0xf7,0xf2,0xff,0x16,0xc2,0x45,0x66,0xc7,0x2e,0x9c,0xf8,0x33,0x93,0xe3, -0x97,0x59,0xbc,0xfb,0x1d,0x42,0xfb,0x9f,0x0e,0x4c,0x34,0xb2,0x37,0x36,0x52,0x68,0xfd,0x0a,0x02,0xfb, -0x32,0xee,0x8f,0x20,0xe1,0xed,0x0f,0xd8,0xfa,0x32,0x4e,0x76,0x78,0x45,0x84,0xc1,0x17,0x76,0x0c,0x3f, -0x95,0xda,0xda,0xab,0x56,0xf1,0xeb,0xe5,0x9b,0x31,0xc0,0xeb,0xdc,0xf9,0xf1,0xa7,0x99,0x85,0xf9,0x11, -0xac,0x26,0x7b,0x21,0xe6,0xc4,0xee,0x8b,0xe5,0x6f,0xe5,0x0b,0x60,0xa1,0x66,0xcf,0xd6,0xe7,0x60,0x14, -0xf4,0x1d,0x63,0xe2,0x7d,0x58,0x1a,0x4c,0x2d,0x6a,0xad,0x64,0x89,0xea,0xe5,0x7e,0xd0,0x0f,0x8e,0xb9, -0x9e,0x63,0x80,0xcd,0xb2,0x99,0xb1,0x7b,0xb7,0x68,0xbc,0x34,0x9b,0xd8,0x81,0x3d,0xe0,0xe6,0xc9,0xf2, -0x72,0xca,0x8b,0x02,0x79,0xc4,0x0c,0x5d,0xf7,0x63,0xf8,0xb1,0x49,0x0a,0xba,0xdd,0x9f,0x8e,0x61,0x52, -0x1f,0x3d,0x18,0x66,0xa9,0x94,0x6b,0x04,0xa3,0xe6,0x7e,0x18,0x83,0xec,0x52,0x50,0x25,0xe7,0x8d,0x1c, -0x7b,0x46,0xf7,0x87,0x77,0x1d,0xc7,0x76,0xb2,0x99,0xdb,0xb3,0x29,0x5e,0x4b,0xc2,0x83,0xc5,0xb8,0x29, -0x3e,0x03,0x0d,0x82,0x57,0xd6,0xb3,0x6f,0xa3,0x8b,0x96,0x99,0xdc,0xa6,0x43,0xe8,0x07,0x11,0x60,0x94, -0xdc,0x53,0x83,0xfe,0x9d,0xcd,0xe0,0xc5,0x0d,0xf8,0xd1,0x55,0x3d,0xb3,0x24,0xc0,0x65,0xed,0x3f,0xb2, -0x7f,0x1a,0x98,0xa3,0xa0,0x2e,0x40,0x83,0x78,0xa5,0xf0,0x97,0x5e,0xd3,0xfb,0xf9,0xd3,0x22,0x9b,0x0f, -0x9a,0xa3,0x58,0x4d,0xaf,0xc0,0x76,0xb4,0x77,0x4d,0x82,0x40,0x64,0x33,0x0c,0xb1,0x00,0x8c,0x55,0x40, -0x5e,0x69,0x42,0x9b,0x02,0xa6,0x1a,0x14,0xb4,0x09,0xde,0x7f,0xb2,0x3d,0x32,0x4c,0x3d,0x6b,0xe5,0x0a, -0x13,0x0d,0xb3,0xc9,0x70,0x2b,0xb4,0x80,0xdb,0xfa,0x0f,0x44,0xbc,0x79,0xf2,0x07,0x74,0x10,0x3d,0x38, -0x8c,0xd7,0x5c,0x5a,0x42,0xbc,0xb3,0x9d,0xa1,0x8c,0x61,0x29,0xf0,0x44,0x0a,0xec,0x51,0xb5,0x9a,0x43, -0x52,0xc0,0xa9,0x41,0x75,0x8e,0x82,0x8c,0xe8,0x03,0x26,0xdd,0xb4,0x96,0x97,0x97,0xa0,0x86,0xe1,0x5e, -0xd1,0x09,0x43,0xad,0xe5,0xe5,0x6c,0x46,0x73,0x1c,0x6d,0x0e,0x24,0x6c,0x5a,0x3f,0x7f,0x96,0xe0,0x1f, -0x98,0x94,0x50,0xd6,0x3e,0x5d,0xbd,0xe5,0x65,0xef,0x43,0x09,0xfe,0x02,0x3e,0xc5,0x41,0x25,0xd8,0x0c, -0x86,0x0c,0x8e,0x71,0x52,0xb0,0x60,0x22,0x18,0x4b,0x41,0xb8,0xc4,0xef,0x82,0x67,0x1f,0x62,0x3a,0xce, -0xb6,0xe6,0x92,0x6c,0x0e,0xc7,0x08,0x97,0x04,0xbd,0xd9,0xd8,0x9b,0x6a,0xf9,0xfd,0x51,0x70,0xf7,0x04, -0x4d,0xbc,0xdc,0x47,0x28,0x18,0x3a,0x64,0x02,0xd5,0x24,0x4a,0x39,0xa2,0xfe,0xd2,0x12,0x90,0x01,0x3c, -0x28,0x2c,0x53,0x49,0x0e,0xe7,0xfc,0x94,0x6b,0x78,0x14,0x90,0x73,0x98,0x4a,0x62,0xf3,0x00,0x78,0x84, -0x8c,0xb7,0xc9,0x20,0xd5,0xad,0x61,0xc0,0x2b,0xde,0xe2,0xb6,0x2e,0x61,0x03,0x7b,0x30,0xec,0x87,0x7c, -0x99,0xf7,0x72,0x07,0x53,0x27,0xae,0xc7,0x01,0x67,0x87,0x11,0xb0,0x0a,0xcc,0xb0,0x91,0xf5,0x9a,0xa1, -0xb2,0x9c,0xfa,0xda,0x01,0x96,0x97,0xcb,0x00,0x31,0xf1,0x67,0xf7,0x94,0x93,0x30,0xa9,0x31,0xba,0x80, -0x77,0x9d,0xdd,0xcc,0x92,0x26,0xf9,0xe6,0xdd,0x00,0xb9,0xb1,0x5d,0xd0,0x60,0xd3,0x5f,0x29,0x24,0x68, -0xe8,0x06,0xcc,0xf6,0xe3,0x69,0x33,0xa0,0x03,0xd1,0xfa,0xa3,0x2c,0x29,0x8c,0x35,0xb0,0xa6,0xb3,0xf7, -0x24,0xf7,0xf3,0xe7,0xb7,0x1b,0x99,0x08,0x40,0x34,0xef,0x9b,0x75,0xd3,0x5c,0x2a,0x3d,0xe5,0x54,0x2f, -0xe8,0x6f,0x2a,0x63,0x38,0x28,0x36,0xb1,0x98,0xad,0x71,0xa9,0xb4,0xcf,0xe8,0x8f,0x14,0x45,0x10,0x8c, -0x4d,0xcf,0x99,0xff,0x00,0x5e,0x0a,0xf3,0x81,0x01,0x73,0x98,0x38,0xf6,0xd8,0x70,0x49,0xee,0xa3,0xc1, -0x29,0x9e,0x2b,0xe0,0xcd,0x26,0x80,0xea,0xc2,0x40,0x33,0x4c,0x58,0x3f,0x8d,0xc4,0x76,0x98,0x60,0x11, -0x34,0xa2,0xcc,0x06,0x0c,0xa2,0xe1,0xe5,0x3b,0x59,0xfa,0x75,0x96,0x92,0xfa,0x8d,0xdc,0x14,0x40,0x9f, -0xf5,0x49,0xd6,0x01,0x8c,0xf6,0xe9,0x84,0x01,0x58,0x2b,0x56,0x2b,0xf7,0x14,0x40,0x3e,0xc8,0x42,0x0d, -0xb1,0x84,0x77,0x1f,0x60,0x49,0x1f,0x1a,0xe0,0xee,0x5a,0x40,0xdc,0xcc,0xce,0xc9,0xd1,0xb6,0x0d,0xa2, -0x1c,0xca,0x50,0x12,0xeb,0x19,0x75,0x90,0x53,0x53,0xea,0xd2,0x0f,0x98,0xe2,0xfb,0x21,0x56,0xd0,0xf4, -0xb9,0xbc,0x3c,0x26,0x59,0xc4,0x99,0xe1,0xa2,0x48,0xd5,0x60,0x0d,0x23,0x07,0xf1,0x9f,0x2b,0x93,0xc2, -0xd4,0xd0,0x57,0x56,0x82,0xca,0x7a,0x80,0xf8,0x8c,0xe7,0x4c,0x09,0xae,0x71,0x02,0x8b,0x9b,0x05,0x57, -0x91,0x11,0x70,0xf9,0xe3,0xdd,0x7d,0xf4,0xcd,0x47,0xfc,0xd5,0xc0,0x35,0xb0,0x42,0x56,0x32,0x99,0x8f, -0x2b,0xa4,0x71,0xc4,0xd9,0x17,0xb0,0x8c,0x57,0xe6,0x14,0xe8,0x07,0xe4,0xe1,0xa9,0x21,0x0b,0x80,0x91, -0x58,0xb2,0x48,0x30,0x67,0x13,0xa4,0x38,0x43,0x50,0x33,0x81,0x43,0x73,0xf0,0xd6,0x01,0x8d,0x85,0xb6, -0x54,0x66,0xc5,0x2b,0xf0,0x6b,0xe7,0xb2,0x6d,0xa2,0x66,0xf2,0xff,0x58,0xce,0xe4,0xc2,0x72,0x01,0x24, -0x1a,0x2c,0x09,0xe2,0xb5,0x3c,0x58,0x8c,0xbd,0xa9,0x87,0x04,0x51,0xc5,0xca,0xf4,0x85,0x13,0x32,0x1e, -0x70,0x89,0xd5,0xa4,0x42,0x93,0x91,0xcb,0xc8,0xfd,0x78,0xea,0x90,0x82,0x4b,0x3c,0x0e,0xdd,0x13,0xc1, -0xc0,0x87,0xd5,0x64,0xb0,0x09,0xb6,0xb6,0x82,0x69,0x0c,0x23,0x9c,0xa7,0xda,0xcd,0xb2,0xaa,0x35,0x2b, -0x25,0xd5,0x6d,0x3a,0x1f,0x7d,0x3e,0xf7,0x59,0xd9,0x29,0xf4,0xa7,0x0e,0xd0,0xa6,0x11,0x7f,0x05,0x44, -0xe9,0xbb,0x2e,0xed,0x2f,0x93,0xc9,0x3d,0xa9,0xd3,0xa6,0x0b,0x73,0x31,0x11,0x1d,0xd6,0xb7,0xea,0xcd, -0xcf,0x9f,0x59,0x56,0xe3,0x98,0x4a,0x59,0x58,0x98,0x1f,0x33,0x99,0x46,0x66,0xf2,0x98,0xc9,0xa9,0xfd, -0x66,0xf4,0x1d,0x10,0x0c,0xde,0x00,0xb5,0xcc,0xe5,0xe5,0x95,0x29,0x2c,0xe1,0x7f,0x20,0xc9,0x49,0x3f, -0x1b,0x8c,0x92,0xcb,0x21,0xd6,0xfb,0xcb,0xcb,0x7d,0xe8,0x1d,0x6b,0xe6,0x7e,0x98,0x4d,0xf3,0xe7,0x4f, -0x7c,0x04,0x14,0x5a,0x74,0xa5,0xf6,0x9b,0x2b,0xd3,0x9f,0x3f,0xcb,0x9b,0xba,0xad,0xd8,0x4d,0x1b,0x7a, -0x2d,0xd4,0x32,0x6a,0xbf,0xd8,0xb4,0x91,0xd1,0xe8,0x47,0x2f,0x29,0xc0,0xfd,0x15,0x33,0xb7,0x49,0xbf, -0x29,0x92,0xb5,0xa1,0xab,0xac,0x8d,0xb0,0x17,0xa7,0x5c,0x74,0xd8,0xcb,0xcb,0xf9,0xbc,0x96,0x7b,0x12, -0xe8,0x03,0x06,0x82,0x7e,0xfb,0x3f,0x7f,0x62,0xdf,0x25,0xd5,0x68,0x5a,0xdf,0xca,0x37,0x1f,0xfb,0x2b, -0x59,0xfc,0x77,0xa5,0x9c,0xfb,0xa7,0xf5,0xad,0x72,0xd3,0x58,0xc1,0xbf,0x55,0x07,0x2a,0x3b,0x05,0x3c, -0x4a,0xd3,0x34,0x55,0xa7,0x40,0xaf,0x59,0x6b,0xf6,0xe1,0x17,0x28,0xc3,0xa6,0x91,0xcb,0xa9,0x46,0x40, -0x8c,0x07,0x5f,0x06,0x51,0x16,0x00,0x03,0x87,0x38,0x3b,0x5c,0xbd,0xab,0x4e,0x33,0xd0,0x2c,0x30,0xe4, -0x17,0xf2,0xcd,0xb9,0x11,0x04,0x35,0x3e,0x1a,0x28,0x58,0xad,0x02,0x1a,0x37,0x61,0x4d,0x1b,0xd1,0xcf, -0x0e,0x8e,0xd8,0xe4,0x48,0x04,0x42,0xe9,0x86,0x0b,0xbc,0x38,0x07,0x1a,0x78,0x69,0x2a,0xd9,0x03,0xe6, -0xb3,0x40,0xc6,0xe0,0x72,0x31,0x60,0x36,0x86,0x70,0x02,0x72,0x2a,0x05,0xa2,0x69,0xa8,0x86,0xb4,0x30, -0xe6,0x81,0x04,0xa6,0x26,0x02,0xa8,0x24,0xa3,0x09,0x94,0xb0,0x9b,0x25,0x60,0x2c,0xa1,0xb5,0x37,0xed, -0xf7,0xda,0xa6,0xbd,0xb2,0x92,0x83,0x69,0x7d,0xb3,0x6f,0x28,0x66,0xe6,0x68,0x5c,0x65,0xad,0x26,0xff, -0x5d,0xe0,0xb0,0xa9,0xde,0xc7,0xac,0x0f,0x00,0xe2,0xde,0x80,0x06,0xcd,0x53,0xba,0x44,0xb2,0x8e,0x34, -0x05,0x30,0x4b,0x60,0x2d,0xab,0xf8,0x1a,0x98,0x2d,0xd2,0x4b,0x13,0x78,0x12,0x26,0x82,0x7d,0x44,0xde, -0x2c,0x2f,0xff,0x85,0x2b,0x4c,0x74,0xfc,0x80,0x38,0x02,0x4d,0x48,0x47,0x5c,0x92,0x46,0x64,0x25,0xea, -0x29,0x5b,0x5f,0xd2,0xc0,0xb0,0xce,0x80,0x17,0x71,0xc2,0x30,0x47,0x7f,0x62,0x08,0xcb,0x52,0x13,0x5b, -0x42,0x07,0x38,0xc7,0x08,0x3c,0xf8,0x26,0x49,0x11,0x8d,0x19,0xfe,0x28,0xee,0xfc,0x05,0xdb,0x4c,0xb2, -0xe3,0x28,0x06,0x38,0x61,0xdd,0xad,0xf9,0xb9,0x36,0x44,0xde,0xf8,0x98,0x5c,0x9c,0x45,0x03,0xe7,0x9f, -0x19,0x98,0x58,0x62,0x4f,0xf7,0x68,0x64,0xb2,0xf3,0x68,0xb6,0xd3,0x32,0xcd,0x8f,0xf1,0x22,0xbf,0x07, -0x20,0xa6,0x2f,0xeb,0xa0,0x0c,0xac,0x24,0x66,0x0d,0xa1,0xb2,0xa7,0x77,0x74,0x65,0x41,0x49,0xa0,0x82, -0x91,0xe4,0xcc,0x63,0x84,0x2b,0x80,0x19,0x9c,0x80,0x19,0xac,0xf7,0xce,0xa6,0x05,0x38,0xe3,0xb8,0x25, -0xa0,0x50,0xd5,0xcc,0xd0,0xb4,0x7b,0x9a,0xb9,0xfb,0xa0,0x99,0x19,0x75,0x09,0xc6,0xe1,0x14,0xf7,0xa2, -0x2f,0x65,0xf5,0xdf,0x13,0xe2,0x0c,0x58,0xd2,0x1f,0xcc,0x56,0x35,0xd5,0x55,0xa7,0xaa,0xa9,0xf6,0xd5, -0x81,0x6f,0xb1,0x8a,0x85,0xb5,0xe7,0x68,0x43,0xba,0x34,0x72,0xea,0x04,0xf9,0x54,0x07,0xd0,0x46,0x01, -0x68,0xfa,0x7b,0xf8,0x3f,0x80,0x06,0xa2,0xc6,0x06,0x56,0xd5,0x81,0x91,0x99,0xc1,0x68,0x63,0x51,0xe0, -0x0a,0xf8,0x46,0xa8,0x9d,0xcb,0xf9,0x78,0x98,0xa8,0x76,0x60,0x84,0x01,0xbd,0x1b,0x76,0x6e,0x93,0x4a, -0x64,0x68,0x7a,0xc6,0xb5,0x0c,0xd4,0xa7,0x90,0x6a,0x4d,0xed,0xe7,0xcf,0x41,0x68,0xf1,0xc6,0x8c,0x6b, -0xf0,0x81,0x90,0x8b,0xdd,0x66,0xf6,0x92,0x8b,0x43,0x1b,0x0d,0x92,0x4c,0x06,0x18,0xfb,0x26,0x07,0xc2, -0x27,0xa2,0x48,0xa6,0xcd,0x6b,0xf2,0xcd,0x85,0xd5,0x70,0x4d,0x0a,0x7f,0x89,0xaf,0xb8,0x69,0x05,0x03, -0x7c,0x5c,0xe7,0xe0,0xfc,0xe8,0xb0,0x39,0x45,0x81,0x05,0xe0,0x8e,0xbc,0xb1,0x79,0xea,0x10,0x6e,0x96, -0xd9,0xb9,0x95,0x29,0xca,0xae,0x3e,0xbc,0x2f,0xdd,0x6c,0xf6,0xf3,0xf9,0xcd,0x1c,0x80,0x57,0xc0,0x74, -0x4c,0x0a,0xd9,0xa6,0x34,0x43,0xad,0xd0,0xc7,0x22,0x9a,0x17,0x99,0x83,0x15,0x3e,0x28,0xd0,0xaf,0x79, -0xd3,0x7a,0xf0,0x12,0x9d,0x00,0x6e,0x05,0xc0,0x12,0x64,0xfa,0x68,0x52,0x98,0x4c,0xdd,0x91,0x3f,0xbd, -0x73,0xa8,0x82,0xcd,0x11,0x15,0x74,0x19,0x0d,0x22,0xad,0x90,0x26,0x9b,0x76,0x73,0xf2,0x0d,0x08,0x71, -0xb3,0x49,0xb5,0x29,0xb3,0x71,0xac,0x16,0x5a,0xf1,0x59,0x1b,0xd4,0x17,0x18,0x87,0x39,0x90,0x4e,0x06, -0xeb,0x5a,0xc2,0xb3,0x49,0xa5,0x1d,0xfb,0x54,0x98,0x9b,0xb5,0x23,0x52,0xd5,0x46,0x90,0xc7,0xd9,0x30, -0xde,0x6d,0x54,0xb7,0xdc,0x8f,0x51,0x41,0x01,0x3d,0x66,0x35,0x50,0xca,0x39,0x04,0xad,0x4f,0x21,0xd1, -0xbe,0xf5,0x29,0x24,0xfb,0x82,0x86,0x94,0xf4,0xb0,0x3c,0x32,0x20,0x46,0x2c,0x1f,0x04,0xbe,0x7a,0x07, -0x01,0x7f,0xce,0x7c,0x75,0x09,0xf6,0xa2,0x5f,0x7a,0x1e,0x94,0x96,0x83,0xd2,0xed,0x2c,0xd3,0xf0,0x42, -0x06,0x90,0x02,0x06,0xd6,0x1f,0x04,0x37,0x04,0x16,0x9a,0x64,0x8e,0xed,0x06,0xfc,0x0f,0x53,0xa3,0x42, -0x04,0x78,0x7f,0x33,0xc4,0xa9,0xc2,0xb2,0x07,0x3f,0x2f,0x6a,0xed,0xa3,0xac,0x73,0x9a,0x0e,0x08,0x52, -0x55,0xd8,0x0c,0x8c,0x22,0x2e,0x4d,0x22,0xce,0x61,0xf7,0x2e,0xed,0xde,0x03,0xb6,0x52,0x6d,0x49,0x7e, -0xc1,0x10,0x28,0xf1,0x40,0xba,0x02,0x06,0xe8,0x0f,0xe3,0x23,0xa8,0x0a,0xa8,0xdb,0xf4,0xbb,0x6a,0xf0, -0x17,0x68,0x80,0xc5,0xcc,0x19,0xac,0xed,0x40,0x6d,0x51,0x97,0x3f,0x4a,0x90,0xa0,0xe6,0x6a,0x36,0x97, -0x80,0xce,0xcd,0x73,0x9f,0xbc,0x4b,0x46,0x4e,0xc0,0x20,0x80,0x41,0xe3,0x0b,0x54,0x36,0xac,0x28,0xd0, -0x4c,0xcd,0x04,0xa7,0x02,0xf8,0x36,0x57,0xb0,0x07,0x03,0x28,0x02,0x0e,0x65,0xe6,0x2d,0x75,0x83,0x35, -0x67,0x48,0xd9,0xc2,0x05,0xf3,0xc5,0x28,0x0c,0xc1,0xb2,0x04,0xae,0xc7,0x7f,0x40,0x9f,0xb0,0x1f,0xc8, -0x4c,0x43,0x6a,0x71,0xe6,0xd0,0x96,0xa5,0xde,0x81,0x64,0x0a,0xa1,0x61,0x8a,0x86,0x6d,0x41,0xd3,0x75, -0xd6,0xa5,0x07,0x94,0x70,0xd0,0x12,0x93,0xa4,0xd4,0x5d,0xc8,0x79,0x44,0xe1,0x99,0xf1,0xf0,0x72,0x10, -0xe4,0x1e,0x23,0x5b,0x46,0x93,0x43,0x72,0xde,0x3c,0x30,0xd4,0xa5,0x25,0x05,0x46,0x6d,0x06,0x45,0x6d, -0x36,0xf3,0xc1,0x43,0x75,0x9f,0x01,0xcf,0x08,0x56,0xe9,0xcf,0x9f,0xa4,0x21,0x69,0x91,0xae,0xec,0x7e, -0x50,0xee,0x6c,0x66,0x99,0x46,0x8a,0xda,0x96,0x19,0x7c,0x09,0x52,0x65,0x25,0x53,0xcc,0xac,0xb0,0xaa, -0xaa,0xd4,0xd1,0x71,0xe0,0x17,0x19,0x1e,0x93,0x39,0xac,0x52,0x10,0x6e,0xf8,0xc8,0x07,0xf0,0x40,0x98, -0x34,0x84,0xed,0x10,0x1b,0x40,0xee,0x74,0x47,0xd2,0x71,0x8c,0x57,0x85,0x88,0x46,0x56,0x2d,0x37,0xe5, -0xf9,0xd3,0x08,0x09,0xc8,0xfe,0x91,0xe6,0xe2,0x85,0x1b,0xcc,0x7d,0xb7,0x51,0xff,0xb3,0xcf,0x18,0x53, -0x22,0x36,0xb9,0xe6,0xa0,0x0b,0xda,0x6c,0xda,0x8c,0x0a,0x2e,0x88,0x56,0x9d,0xa7,0x87,0x43,0x7b,0x4b, -0x37,0x09,0xd0,0x9b,0xbd,0x42,0x2f,0x0f,0x39,0xdb,0x40,0xce,0x36,0xe9,0xda,0x66,0x4a,0xc9,0xfc,0x66, -0xdc,0x44,0xf5,0x52,0x98,0xac,0x00,0x2f,0x56,0x02,0x3d,0x94,0x43,0x6b,0x3b,0x04,0x98,0xdb,0xec,0xc8, -0x80,0x4d,0x99,0xab,0x02,0x72,0x4c,0xcf,0xfe,0x78,0x52,0x41,0x40,0x76,0x04,0xa0,0xd3,0x9c,0xec,0x47, -0xdd,0x4a,0x18,0xe1,0x93,0x8f,0x87,0x10,0x36,0x33,0x34,0xbc,0xc5,0xed,0xa0,0x0b,0xe1,0xa6,0x30,0x72, -0x7c,0x04,0x71,0x8a,0xf9,0x03,0x44,0x07,0x0a,0xf3,0x5f,0x0d,0xde,0x80,0x99,0x31,0x34,0x78,0x07,0x36, -0x9e,0x46,0x9f,0x81,0xa5,0xbd,0x02,0xd7,0x09,0x97,0x74,0x07,0x8b,0x84,0x1e,0x25,0x7e,0x6d,0x51,0xa9, -0x42,0x75,0xaa,0xd7,0xb4,0x09,0x5f,0x31,0xa0,0x2b,0xbd,0xdc,0x66,0x5c,0xc1,0x96,0x40,0x8f,0xfa,0xc1, -0x19,0xbd,0x39,0xc9,0x97,0x41,0x9f,0x7a,0xc0,0xa2,0xea,0xb0,0x19,0x76,0x4c,0x47,0xd4,0x82,0x1f,0xfe, -0xfc,0x39,0xf9,0x50,0x06,0xf0,0xa2,0x22,0x61,0xb4,0xbc,0xbc,0xa4,0xf3,0xb9,0x6c,0x9b,0x60,0x7c,0x2d, -0x2f,0x3b,0x1e,0x9b,0xf3,0x28,0xe7,0xaf,0xfa,0xc8,0x1a,0xe4,0x1e,0x19,0xe8,0xea,0x02,0xb9,0x87,0xa7, -0xcd,0x21,0x50,0x05,0x47,0x6f,0x8e,0x78,0x24,0x01,0x57,0xa5,0x05,0x8a,0x19,0x75,0x5e,0x16,0x2c,0x37, -0xb5,0x05,0x0a,0x84,0x4d,0xef,0x89,0x02,0x34,0xa1,0x0c,0xd6,0xc3,0x98,0x03,0xb4,0x8b,0x28,0x8c,0xa5, -0xb2,0x0a,0xe6,0x37,0xb2,0x9c,0x2d,0xaf,0x4a,0x2a,0x73,0x24,0x4d,0xc8,0xe7,0x4f,0x7b,0x02,0xe5,0x01, -0xaa,0xdd,0xe0,0x7a,0xde,0x45,0x24,0x8c,0xb5,0x49,0x76,0x0c,0xc3,0x06,0x6a,0xa6,0x8b,0xcc,0x22,0x9a, -0x6d,0x0e,0xde,0x4f,0x36,0x07,0xc0,0x78,0xc0,0xca,0xea,0x00,0xa8,0xa5,0x43,0x47,0x4c,0x91,0x21,0x1e, -0xb2,0xa6,0xba,0x54,0xc2,0x40,0xa2,0x3a,0xa5,0x7a,0x90,0xa9,0x62,0x57,0x1d,0xc3,0x0b,0xbf,0x47,0x98, -0x98,0xc3,0xdd,0xfd,0x6f,0x83,0x1b,0xa0,0xcd,0x80,0x4e,0x6e,0xca,0xd5,0x98,0xfb,0x4d,0x0c,0x96,0x2f, -0x47,0xe7,0xc8,0x01,0x74,0xd5,0xe3,0x1c,0xd2,0x13,0xa0,0x99,0x72,0x68,0x5c,0xec,0x4a,0x68,0x3d,0x53, -0xd6,0x7a,0x4b,0xc1,0x82,0x34,0xc3,0xe6,0x19,0x05,0xd1,0x57,0xc0,0x7d,0xd5,0xc4,0x75,0x62,0x16,0x5c, -0xa7,0x8f,0x06,0xe3,0x5f,0x04,0x2a,0x5d,0x38,0x26,0xad,0x25,0x1e,0xd8,0x6b,0xd0,0x17,0x38,0x46,0x60, -0x0a,0xf8,0x8e,0xb3,0x4d,0x5d,0x4c,0xb5,0x9f,0xf3,0x7d,0x32,0x49,0xb8,0xdc,0x0b,0xcf,0x5c,0xd8,0x7f, -0xe8,0x80,0x78,0xe1,0x48,0x14,0xf8,0xf2,0xe8,0x90,0x6c,0x32,0x91,0x08,0x3a,0x8f,0x59,0xe3,0xd4,0x6e, -0x07,0x77,0x71,0x09,0x9d,0x04,0x21,0x80,0x7e,0xfe,0xa4,0x78,0x27,0x9a,0x45,0x97,0xf9,0x98,0xfa,0x50, -0x8e,0xe4,0x2d,0xa1,0xd3,0x12,0x9e,0xa4,0x13,0xf5,0xdd,0x72,0x68,0x44,0x8c,0xd1,0x69,0xf0,0xc9,0x13, -0xea,0x22,0xe4,0x70,0x41,0xff,0x09,0x7e,0xc1,0x61,0x28,0xe0,0x20,0x64,0x66,0x93,0x7b,0xb1,0x81,0xa7, -0x00,0xf0,0x4f,0x31,0x76,0xa1,0x5a,0x54,0x05,0x5a,0x28,0xed,0x4f,0xe9,0x21,0x25,0x6f,0x4e,0x17,0x36, -0x38,0x74,0xa0,0xe0,0xc1,0xc7,0x06,0x1c,0xc2,0x44,0x35,0x36,0x3f,0x01,0x7a,0xd4,0xed,0xc4,0x88,0x17, -0x74,0x23,0x7b,0xcb,0x00,0x3b,0xae,0xcb,0x89,0xf1,0x48,0xcc,0x23,0x50,0x99,0x86,0xd5,0xc1,0xad,0xae, -0x2c,0x4c,0xd2,0xe5,0xeb,0x53,0x83,0xdf,0x9a,0x27,0xa2,0x80,0xd4,0xaa,0x70,0x0b,0x33,0x43,0x07,0x89, -0x60,0xc0,0xaf,0xb1,0x61,0x5d,0xd1,0x07,0x1b,0x1f,0xb4,0x47,0xf6,0x10,0x94,0x4b,0xa5,0xa2,0x5d,0x53, -0x53,0x71,0x32,0x33,0x5e,0x93,0x95,0x39,0x72,0x1b,0x43,0x95,0x5a,0x81,0x29,0xc9,0x9d,0x14,0x9c,0xe2, -0x47,0x6d,0x25,0x93,0x69,0x68,0x01,0x32,0x0f,0x64,0x0d,0x0c,0x5a,0xdb,0x4b,0x88,0x67,0x80,0xc0,0xfd, -0x48,0xbb,0xe0,0x2a,0x84,0x46,0xa0,0xb0,0x6a,0x56,0xfc,0x6a,0x7a,0xb9,0x14,0xeb,0x41,0x92,0xec,0x7b, -0x3c,0xc8,0x4f,0xcf,0xcc,0x8f,0xbc,0xc0,0x5a,0x11,0xec,0xe9,0x35,0xa9,0x98,0xf1,0xec,0x0b,0xfc,0x6c, -0x3c,0x93,0xf4,0xa0,0x88,0x59,0x28,0xae,0x8c,0xd1,0x20,0xdd,0xf3,0x15,0x12,0x9a,0xe2,0xd8,0x19,0x94, -0x81,0xfe,0x59,0x01,0xfa,0x44,0xba,0x0d,0x06,0x3e,0x09,0x34,0x37,0xf3,0xf7,0x91,0x0b,0x5c,0x70,0xcd, -0x7c,0xc5,0x8d,0x2a,0x20,0xf2,0xae,0x89,0xe0,0x82,0x2d,0x11,0x8a,0x65,0x9e,0x86,0x58,0xaf,0x29,0x42, -0x31,0x9e,0xcf,0xa6,0xce,0xc7,0x23,0xcd,0x1b,0x21,0xf6,0xb3,0xa0,0x42,0xc1,0x75,0xc8,0x67,0x31,0xac, -0x0e,0x46,0x45,0xd6,0xa1,0xa1,0x1f,0x1a,0xe6,0x69,0x48,0x5d,0x76,0x64,0x47,0x8d,0xeb,0x10,0x94,0x34, -0xd4,0x89,0xb6,0x40,0x98,0x66,0x9d,0x8f,0x99,0x1e,0xfd,0xcc,0x5d,0xa6,0x91,0xe9,0xb3,0xf5,0x0f,0x76, -0xcf,0x6a,0x23,0x43,0x49,0x8f,0x3a,0xd0,0xfb,0x58,0x6e,0xa0,0xbf,0xbd,0x0a,0xeb,0xb6,0x59,0xc9,0x65, -0xc6,0x94,0x17,0x45,0x94,0x40,0x5b,0x69,0xfa,0xb1,0x22,0x6b,0x65,0x8b,0x46,0x19,0x40,0x6a,0x62,0xc8, -0xc5,0xf9,0x98,0xf5,0xbb,0x14,0xb5,0xf3,0x41,0xed,0xcc,0x04,0xd4,0x3c,0x6a,0xa2,0x70,0x2b,0xd1,0xff, -0x52,0x42,0x0b,0x0e,0x29,0x6b,0xb0,0x92,0xa1,0x3c,0x98,0xe1,0x0d,0xc1,0x94,0x95,0x61,0x49,0xec,0x3d, -0x28,0x5d,0x8a,0x43,0xbf,0xb8,0x77,0x41,0x03,0x89,0xbb,0x8f,0x22,0xa2,0xa2,0xc9,0x04,0x82,0xdd,0x64, -0x32,0x84,0x6a,0x2f,0xde,0x69,0x1e,0xd3,0x0d,0x99,0xf7,0xea,0x0f,0xf6,0xd8,0x35,0xbe,0x23,0x28,0xa8, -0xeb,0x0c,0xbf,0x7f,0xb1,0xb4,0xed,0xdc,0x47,0xbb,0x01,0xeb,0x59,0x03,0x28,0x41,0x0a,0xf8,0xd5,0x3b, -0xc4,0x34,0xd0,0x88,0xcd,0x02,0xfb,0xd8,0x34,0xfc,0x49,0x05,0x06,0x06,0xe0,0xd5,0x0c,0xe6,0xb9,0x66, -0xb8,0x59,0x8e,0x6e,0x74,0x86,0xdd,0x07,0x9c,0x59,0xf1,0xe2,0xac,0xef,0xf9,0xac,0x7f,0x83,0x30,0xd3, -0xe8,0xeb,0x9e,0x69,0x6b,0x1e,0x75,0x76,0x4b,0xaa,0xbd,0xc2,0x99,0x07,0x05,0x53,0x12,0x93,0x50,0xa6, -0x5a,0xa1,0x2c,0x17,0xe0,0xa4,0x2d,0x33,0x9c,0xef,0x52,0xcd,0x94,0x36,0x86,0xd4,0x3d,0x1b,0x35,0x19, -0xf8,0x93,0x86,0x27,0x55,0x0b,0x1a,0x5f,0x81,0x54,0x78,0xf0,0x50,0xce,0x83,0xb9,0x67,0xe8,0x3a,0xb1, -0xa8,0x23,0x82,0x9b,0x3d,0xfc,0x53,0xd6,0x2d,0xcb,0x18,0xd3,0x7c,0xf9,0x3d,0x87,0xc5,0x60,0x12,0xcb, -0xb3,0x57,0xa0,0x78,0xd0,0xfe,0xc3,0xf4,0x31,0x1b,0xa8,0x72,0x85,0xba,0x76,0xf0,0x58,0x10,0x37,0x3b, -0xe5,0xf8,0xb3,0x67,0xf4,0xef,0xb2,0x72,0x60,0xe3,0x1f,0x92,0x5c,0x92,0x3b,0x90,0x7d,0x0f,0x8f,0x3b, -0x4a,0x4f,0xd0,0x0b,0x5d,0xd7,0x96,0x3d,0x93,0xc3,0xe8,0x5b,0x21,0xab,0xbb,0x89,0x81,0xcb,0x1f,0x23, -0x82,0xa2,0x1b,0x3c,0x07,0xba,0xf4,0x3c,0xbe,0xa6,0x1c,0x58,0x53,0x0e,0xac,0xa9,0xbc,0x97,0xb3,0x9a, -0x5b,0x18,0xe4,0x53,0x8d,0x6f,0x82,0xff,0x57,0xac,0x1b,0x50,0x97,0x01,0x1b,0xc3,0xa3,0xaf,0x7e,0x10, -0x47,0x46,0xc1,0x9e,0x68,0x7d,0xc3,0x9b,0x37,0x0d,0x2e,0xa6,0x49,0x28,0xca,0xf9,0x57,0x92,0x7e,0xce, -0x5e,0x14,0xe8,0x45,0x15,0xc4,0x71,0x69,0xf4,0xf7,0xdb,0x4d,0x0e,0x75,0x12,0xf8,0xb8,0xf2,0x9b,0xcc, -0x3f,0x33,0x94,0x27,0x30,0x92,0x68,0x44,0x23,0x89,0x34,0xc8,0x8e,0x7a,0x9c,0x59,0x3d,0x96,0x8a,0xca, -0x4b,0xc8,0x45,0x27,0x18,0xff,0x7b,0xa2,0x22,0xf5,0xcd,0x57,0x2e,0x5f,0x0c,0x2a,0x1f,0x33,0x0c,0x3f, -0xf4,0x09,0xcc,0x5a,0x2a,0xe6,0x75,0x70,0x1d,0x68,0x84,0x88,0xf2,0x37,0x18,0xb5,0x41,0xa0,0x9f,0x86, -0x12,0x61,0xb6,0x0f,0x22,0x3c,0x09,0xeb,0x69,0xf0,0x88,0x67,0x8e,0xe9,0x86,0x28,0xbd,0xfc,0x5e,0xa8, -0xd3,0xbf,0xe8,0xd3,0x81,0x6d,0xdf,0xb9,0xac,0x1a,0x30,0x2e,0xf3,0x8f,0xb5,0xc2,0xd4,0x62,0xf7,0xe4, -0xa3,0x20,0xf0,0x1f,0x9a,0x18,0x93,0x07,0xf7,0x05,0x4f,0x6a,0xa0,0xe9,0x49,0x7d,0x19,0xff,0xa1,0x29, -0x71,0x42,0xd0,0xe6,0xe7,0x4f,0x17,0x38,0x00,0xbd,0x5c,0x51,0xb2,0xb2,0xa2,0x4e,0x0a,0xec,0x5b,0xd8, -0x32,0xf3,0x24,0x95,0x05,0x8d,0xf2,0x79,0xe4,0x4b,0xfa,0x5b,0xc0,0xca,0xb1,0xff,0xf3,0xa7,0x0c,0x04, -0x8e,0xf5,0xc4,0x83,0x38,0x0e,0x0b,0x19,0x00,0x55,0xc0,0xfa,0x42,0x0e,0x9a,0x73,0x01,0x82,0x86,0x30, -0x94,0x0a,0xad,0x8a,0xaf,0x58,0x68,0x9e,0x7d,0xe1,0x86,0x86,0x99,0xa9,0xa7,0x9f,0x1d,0x7e,0xcc,0xc0, -0x6a,0x23,0xb0,0xb6,0x19,0x0a,0x69,0x3b,0xf6,0x1b,0xc4,0xa4,0xf1,0xf3,0xe7,0xd2,0xc3,0xcf,0x9f,0x7e, -0x28,0xf2,0x01,0x7a,0xca,0xa1,0x10,0x30,0xac,0x29,0xd9,0x1c,0xe2,0x8e,0x9c,0x8e,0xe1,0xe9,0x87,0xe5, -0x65,0x7c,0x45,0xcd,0x1c,0x61,0xc3,0x38,0x39,0x0c,0x58,0x4c,0x9b,0x6c,0x63,0x78,0x17,0x27,0x70,0x42, -0xe3,0x23,0x18,0xed,0x9e,0x42,0xc7,0xb1,0x72,0x1d,0xcd,0xf7,0xe8,0xc6,0x0e,0x4a,0x84,0x02,0xd8,0x6d, -0xce,0xc0,0xb4,0x67,0xcd,0x6f,0x23,0xff,0xb7,0x1a,0xfc,0xfc,0x22,0xfd,0xbe,0x06,0x3b,0x9c,0xc2,0xe3, -0xc7,0xb6,0x19,0xc5,0x4d,0x6a,0xde,0x07,0x3c,0xe3,0x87,0xb4,0x71,0x6b,0x24,0x10,0xcd,0x41,0xb0,0xde, -0x8f,0x87,0xf7,0xb1,0xe5,0xc7,0x7e,0xd3,0x6c,0x64,0xe7,0x34,0xec,0x8a,0x5e,0x81,0x29,0x98,0x53,0x0c, -0xf3,0xf3,0xa7,0x99,0xd2,0x11,0x6d,0x84,0xbe,0x42,0x16,0x78,0xdc,0x34,0x78,0xa7,0x40,0x0c,0xf6,0x94, -0x67,0x91,0x7e,0x36,0x10,0x33,0x96,0xd1,0x7c,0xf7,0x87,0x0f,0xba,0x1c,0xa0,0x84,0x46,0x63,0x3f,0x0b, -0xe8,0xcb,0x4e,0xd8,0xae,0xa4,0xc4,0x4c,0x23,0x3f,0xf0,0x6d,0x3e,0xe5,0xa4,0x69,0xf7,0x9b,0xfe,0x1b, -0x80,0x3b,0x98,0x17,0x6e,0x0e,0x81,0x7d,0xaf,0x06,0xed,0xc2,0x20,0xc1,0xab,0x00,0xf5,0xd0,0x4f,0x80, -0xe4,0x66,0x86,0x89,0xe8,0x4c,0x22,0xa3,0x4b,0xf5,0x82,0xf6,0xe8,0x9c,0x4a,0x14,0x93,0xdf,0x94,0xe5, -0x37,0xd7,0xf2,0x9b,0xca,0x0d,0xb0,0x3a,0x38,0x6d,0x4b,0xe5,0x80,0xdf,0xf5,0x1c,0xce,0xfe,0xe1,0xa3, -0x00,0x01,0x8a,0x80,0xdc,0xd9,0x61,0xf3,0x81,0xeb,0x8d,0x5c,0xe3,0x41,0x0e,0x5d,0xf8,0xe2,0x41,0xfd, -0xc1,0xa7,0xd9,0x40,0xf4,0xa0,0x9a,0x14,0x2d,0x80,0x47,0x41,0x9e,0x2f,0x2f,0x07,0xe4,0x8d,0x23,0x17, -0x5c,0x68,0x46,0x48,0xdc,0x9d,0x60,0xae,0x44,0x48,0xf4,0x48,0xf0,0xc9,0x8b,0x40,0xc5,0xf5,0x91,0x63, -0xb3,0xf8,0x0b,0x56,0x1b,0x2e,0x93,0x06,0x18,0x70,0xea,0x04,0x74,0x28,0x56,0x7f,0xc0,0xc9,0xe0,0x1a, -0x9a,0xb2,0x8d,0x2b,0x84,0x23,0x3b,0xa5,0x5b,0x57,0xa2,0x84,0xff,0xdb,0x2c,0x85,0xc2,0x19,0x5f,0x12, -0x02,0x3c,0x14,0x0a,0x8b,0x25,0x52,0x50,0x59,0x8d,0xcc,0x03,0x4a,0xd1,0xa4,0x7a,0xdf,0xc2,0xe8,0x1e, -0x17,0x06,0x34,0xfe,0x4f,0x43,0xbb,0xb0,0x08,0x79,0x88,0x97,0xee,0xcf,0x34,0x6d,0xa4,0x07,0xab,0x00, -0xbf,0x4b,0x30,0x61,0x6b,0x89,0x86,0x1c,0xb3,0x74,0x27,0xca,0x56,0xb9,0x54,0xc1,0x0a,0x68,0xe5,0x30, -0xfe,0xa4,0x42,0x16,0xbb,0x06,0x9b,0x25,0xc3,0x36,0x8e,0x91,0x32,0x5a,0xee,0x87,0x8d,0x02,0x95,0x16, -0x60,0xd0,0xd7,0x6f,0xec,0xdc,0x04,0xc0,0xda,0x39,0x06,0x33,0xa0,0x82,0x0f,0x0b,0xc0,0xd1,0x2d,0x7f, -0x83,0x6f,0xaf,0x7a,0x74,0x13,0x2c,0x98,0xfc,0x45,0x4c,0xc1,0x50,0x85,0x75,0x01,0x96,0x06,0x8f,0xb0, -0x0b,0xd7,0x5b,0xa5,0xc1,0x80,0x1d,0x32,0x20,0x8e,0x43,0xf4,0x6c,0x2e,0x81,0x5f,0x39,0x4c,0x80,0x74, -0x93,0x8c,0x9f,0x90,0x52,0xd2,0x4b,0x14,0xae,0x39,0x11,0x39,0x96,0x1c,0x8a,0x21,0xa8,0xae,0x7f,0xd0, -0x8d,0x64,0xc9,0x2e,0x37,0x19,0xa5,0xd0,0x72,0x58,0x31,0x0b,0x3a,0xbf,0xc7,0x03,0x54,0x3c,0x46,0x59, -0x8b,0x41,0x09,0xb5,0xb1,0x9a,0xe5,0xbc,0x83,0x16,0x39,0x8c,0x67,0x32,0xfd,0xeb,0xc7,0x26,0xb4,0xf7, -0xd3,0x4d,0x0d,0xa3,0x01,0xbc,0xfc,0x9b,0x76,0x53,0x70,0xa6,0x96,0x14,0xf0,0x76,0x0b,0xf4,0xc6,0xeb, -0xf9,0x95,0xe1,0xe1,0x36,0xf9,0x37,0x13,0xc8,0x8f,0xf4,0xb0,0xdf,0x83,0xc9,0x34,0xfd,0x68,0x35,0x50, -0x46,0xc4,0x2b,0x95,0x55,0x24,0xa8,0x0b,0x0c,0xec,0xda,0xe6,0x03,0xf1,0x5f,0x40,0xe1,0x52,0x39,0xf7, -0x04,0xe2,0xc1,0x15,0xf9,0x0f,0xd9,0x1f,0x88,0x0e,0x70,0xe2,0xf1,0xfa,0x0d,0xb7,0x11,0x0a,0xb2,0xc1, -0x84,0xec,0x89,0x27,0x17,0x82,0xa5,0xfc,0xc3,0x9d,0x90,0xbe,0xa1,0x99,0xbb,0x1a,0x9e,0x6a,0x6a,0x40, -0x35,0xc2,0x7e,0xd1,0x14,0x0f,0xfc,0xe5,0x6f,0x90,0x3c,0x01,0xe9,0x54,0xdb,0x31,0x86,0x78,0xa1,0x0e, -0xf7,0x9c,0x0d,0xe2,0x36,0x3c,0xbf,0xf0,0x84,0x66,0x77,0xbb,0x0d,0x4b,0xf5,0x31,0xda,0x10,0x28,0x17, -0x58,0x6c,0x58,0x3e,0x42,0x55,0x86,0x27,0xdc,0x37,0xe3,0x1b,0x1e,0xf8,0x1c,0x78,0x9c,0x92,0x6b,0x05, -0xd0,0xd0,0x97,0x30,0x6f,0xb3,0x80,0xb3,0xa0,0xc6,0x28,0xfb,0x59,0x08,0x4d,0x81,0x5a,0x49,0xfc,0x05, -0x9b,0x80,0x8f,0x7e,0x9f,0x60,0x74,0x1f,0xc2,0x01,0xfa,0x3e,0x01,0xa0,0xf6,0x44,0x1a,0x51,0x44,0x1a, -0x31,0xe0,0xe9,0x7d,0x8c,0x50,0x18,0x0c,0x40,0x89,0xb1,0xa8,0xdf,0xcb,0x42,0xa5,0xa0,0x52,0xfd,0x90, -0xa8,0x4f,0x7d,0x8b,0x51,0xbf,0x2c,0xc5,0x83,0xb3,0x2f,0xa7,0xad,0x0a,0xee,0x41,0xae,0x81,0xe5,0xa8, -0x65,0x43,0xc5,0x2a,0x0e,0xfc,0xf4,0x84,0x2a,0xd0,0x2c,0x50,0x3a,0x53,0x28,0xbe,0x60,0x08,0x29,0x01, -0x21,0xb9,0xb0,0x21,0x28,0xaf,0x36,0xdf,0x26,0x34,0x55,0xa2,0x8a,0xd6,0xbe,0x69,0x18,0x8e,0x49,0xe2, -0xe6,0xb0,0x3d,0x41,0x69,0x13,0xb1,0xd1,0x4c,0xba,0x02,0xc5,0xd0,0xf4,0x45,0x8e,0xd6,0x45,0xa2,0x01, -0x78,0x8f,0x73,0xde,0x56,0xa5,0xf1,0x21,0x29,0x85,0x08,0x63,0x69,0x7d,0xf5,0x2f,0x95,0x59,0xf7,0xd2, -0x58,0x62,0x1a,0xc8,0x44,0x30,0xa2,0xfc,0x28,0x12,0x75,0xa0,0x0d,0x9d,0x3c,0xfd,0xcc,0xbd,0x68,0x20, -0x9e,0x79,0xee,0x0f,0x2f,0xc5,0xdf,0x02,0x3c,0x71,0xa6,0x90,0x67,0x05,0xf1,0x52,0xfc,0xed,0xcb,0x18, -0x5e,0xc6,0x9e,0x02,0xbf,0x63,0x4c,0x9c,0x6c,0xb0,0x72,0xa6,0xaa,0x58,0x68,0x1a,0x38,0x32,0x0d,0x53, -0xa5,0xf3,0x6e,0xc8,0x48,0x40,0xf5,0x61,0x06,0xc2,0xef,0x32,0x88,0x3a,0x44,0xb2,0xa6,0x7c,0xfe,0x28, -0xdc,0xda,0x86,0x95,0xcd,0x28,0xb2,0x7b,0xb6,0x1f,0xda,0xaf,0x90,0x37,0x28,0xd0,0xc9,0x0a,0x6f,0x58, -0xd0,0x14,0x52,0xdc,0xee,0xcf,0x64,0x82,0x0e,0xae,0xa3,0x29,0x54,0xc0,0x05,0x61,0x15,0xe2,0xd1,0x8d, -0x59,0x1a,0x2d,0xf6,0x54,0x69,0xf1,0x81,0x3f,0x08,0x32,0x6f,0xc7,0xf3,0x93,0x7e,0x9c,0x2c,0x46,0x78, -0x1b,0xd0,0xe3,0x4a,0xe6,0x5b,0x66,0x25,0xbe,0x75,0x66,0x08,0x5b,0xc8,0xf8,0xe8,0x35,0x32,0x19,0xf0, -0x35,0x6f,0x32,0x20,0xe6,0x71,0xf0,0xa7,0x60,0xe3,0x11,0x3a,0x15,0x2d,0x97,0x82,0xed,0x61,0x80,0xc2, -0xa1,0xca,0x91,0xd5,0xf3,0xb7,0x20,0xbc,0x9c,0x18,0xcf,0xa0,0xdd,0x79,0xdf,0x8c,0x1b,0xd6,0xa3,0x3f, -0xc5,0x33,0x09,0x47,0x61,0xe1,0x11,0x4f,0xdb,0xa3,0x89,0x14,0x9e,0xea,0x35,0x71,0xc7,0x7e,0x53,0x78, -0x59,0x28,0xd8,0x23,0x49,0x88,0x11,0x1a,0x61,0x3c,0x3e,0xc4,0xa3,0x56,0x8e,0x06,0x8c,0x37,0x1d,0x50, -0x7c,0x06,0xdd,0xf4,0xcc,0xac,0xd0,0x24,0x0a,0xd0,0xbe,0x1f,0x71,0xb3,0xd0,0xf7,0xd6,0x69,0x76,0x80, -0xca,0x14,0x31,0xa1,0x06,0x37,0x3a,0x71,0x53,0xcb,0x1d,0x19,0x03,0x0f,0xfb,0x69,0x44,0xdf,0x51,0xf9, -0x64,0xc9,0x76,0xc3,0xa7,0x80,0x8a,0x52,0xaa,0xa5,0xcb,0x68,0x3a,0x15,0x1c,0x64,0x7f,0x73,0x31,0xe1, -0x4e,0xf5,0xd3,0xf3,0xe8,0x1e,0x77,0x38,0x2f,0x8f,0xb7,0x01,0x9d,0x91,0x65,0x1d,0x8a,0xd4,0xd0,0x28, -0xaa,0x4c,0x70,0x61,0x7e,0xfe,0xb4,0x41,0xcd,0x7c,0xd4,0x3e,0x2e,0x81,0x4f,0x60,0x82,0x8d,0x46,0x7d, -0x8a,0x06,0x6e,0x90,0x68,0x9e,0x86,0x96,0xbe,0xeb,0x4f,0x04,0x56,0xa4,0x81,0x7f,0xa1,0x4a,0x02,0x75, -0xfc,0xc4,0x76,0x1b,0x40,0xa1,0x68,0x4d,0xcc,0x22,0xbb,0xf2,0xfc,0xa4,0x1c,0xb9,0x39,0xda,0x2a,0xe0, -0x56,0xd8,0xd4,0x85,0xc5,0x5d,0x3e,0xa4,0x4b,0x30,0xef,0xcf,0x11,0x7b,0x09,0xd9,0x45,0xbb,0xd5,0x1e, -0xbb,0xc4,0xf3,0xe8,0x05,0xcf,0x03,0x53,0xf3,0xb8,0xda,0xf9,0xf9,0x93,0x6f,0x5d,0x59,0x8c,0x6f,0xfc, -0x30,0x27,0x1a,0x25,0x40,0xf7,0xac,0x01,0xff,0x7e,0x24,0x0d,0x07,0x93,0x60,0x00,0xb0,0x5c,0x0e,0x8d, -0x15,0x7c,0x19,0xc4,0xeb,0x68,0xb8,0x3a,0xd0,0x8e,0xe8,0x10,0xc9,0xfb,0x73,0x5f,0x13,0x5c,0x74,0x3f, -0xde,0xcc,0xe3,0x2c,0xe0,0x31,0xe3,0x8e,0x91,0x98,0xe0,0x26,0x4c,0x08,0xa6,0x4f,0x13,0x06,0x72,0x60, -0x14,0x52,0x5c,0xe5,0x82,0x44,0x11,0x9a,0x07,0x85,0x22,0x01,0x24,0x0c,0x8b,0xaa,0x7b,0xb8,0xac,0x3b, -0xc4,0x9d,0xc0,0x9c,0xc8,0x01,0xbd,0x8d,0x2c,0x9b,0xe1,0x91,0xfe,0xfc,0x39,0xdb,0x94,0x44,0x7e,0x74, -0x72,0xfe,0x22,0x71,0x51,0xb6,0xbb,0xb0,0x32,0x96,0x97,0xf1,0x6f,0xb6,0x62,0x41,0xdc,0xfe,0x98,0xfa, -0xe4,0x31,0x72,0x9b,0x3d,0x50,0xb2,0x77,0xd4,0xbf,0x03,0x60,0xa0,0x95,0x95,0xb3,0x19,0x5c,0xb8,0xe2, -0x7e,0xf8,0x9d,0x59,0x2c,0xf7,0x7a,0xca,0x36,0x4f,0x71,0x5a,0x78,0x0d,0x1b,0xaa,0x0b,0x58,0x81,0x4a, -0x66,0x05,0x5f,0xdc,0xa0,0x89,0x68,0xf0,0x1e,0x35,0xea,0xba,0x83,0xd5,0x47,0xdd,0x55,0x0d,0x47,0xb0, -0x85,0x12,0xc1,0xac,0x31,0x6c,0x00,0xf6,0x8d,0x0f,0x0a,0x58,0x94,0x16,0xa8,0x9e,0x00,0xad,0x84,0xc4, -0xb2,0xed,0x44,0xe8,0x01,0x19,0xa8,0x2f,0xe3,0x93,0x2f,0x2b,0x96,0xe3,0x06,0x56,0x2f,0x45,0x82,0x46, -0x2d,0x51,0x09,0xd4,0x9c,0xf9,0x4d,0x0b,0xaf,0xe7,0x9b,0x66,0x68,0x2a,0xda,0x0d,0x8f,0xa9,0xf6,0x05, -0x49,0x36,0x6d,0x16,0x41,0x46,0x55,0x4c,0x51,0xbf,0x47,0xaf,0xb0,0x62,0x79,0x4a,0xd6,0xb7,0x84,0x72, -0x60,0x1e,0x60,0xf7,0xe9,0xf2,0xb2,0x83,0xb2,0x18,0x21,0xdc,0xa3,0x7a,0x15,0x37,0xd6,0x9a,0x72,0x01, -0xee,0xac,0xf8,0x33,0xa0,0x5e,0x85,0xad,0x4a,0x23,0xd3,0x84,0x19,0xca,0x25,0x36,0x52,0xc4,0x17,0x94, -0x50,0x86,0xd8,0x03,0xd4,0x61,0xae,0x1d,0xa5,0x8a,0xd6,0x34,0xbf,0x4d,0x29,0x15,0x30,0x97,0xcb,0x84, -0x55,0x43,0x7f,0xaa,0x4b,0x5a,0x4e,0xda,0xb4,0x45,0x66,0x68,0x1a,0x60,0x06,0x98,0x86,0x47,0xf5,0x89, -0xea,0x02,0xa6,0xfc,0xdd,0x7f,0xd1,0x05,0x2e,0xbe,0xa0,0x17,0xfa,0x04,0x2c,0xa3,0x61,0x08,0xaf,0xf4, -0x51,0xa3,0x1b,0xbe,0x0d,0xfc,0x6b,0x09,0x0b,0x68,0x80,0x12,0xeb,0xa8,0x7d,0x9f,0x90,0xd8,0x6b,0x4e, -0xe2,0x2b,0x8d,0xd6,0xc4,0xe1,0xc1,0xa1,0x20,0xdf,0x32,0x34,0x9f,0xd7,0xcd,0xdc,0xe4,0xbc,0xa6,0x96, -0x15,0x92,0x1d,0x53,0x37,0xd8,0x33,0xcf,0xd4,0x18,0xf8,0xfb,0x0d,0xf4,0xbb,0xbd,0x8d,0x0c,0x8d,0x6c, -0x3a,0x04,0xd3,0xfc,0x33,0x2a,0xfd,0xa7,0xa1,0x7d,0x1c,0x34,0x32,0xc7,0xb6,0xc2,0x28,0x48,0xbf,0xb1, -0x44,0x3f,0x17,0x03,0xdc,0xb8,0x42,0xef,0x0a,0x04,0x2c,0x3c,0x3d,0x3d,0x85,0xfb,0x71,0xa7,0xd4,0x9b, -0xcc,0xa8,0x88,0xfa,0x86,0xf7,0x44,0x45,0x92,0x47,0x30,0x99,0xc9,0x22,0xd2,0xf1,0x03,0xd5,0x21,0x4d, -0x16,0xcd,0xe0,0x7b,0x42,0x2c,0xec,0x79,0x32,0x50,0x0d,0xd2,0xf4,0xf8,0x8e,0x83,0x6a,0xd3,0xdf,0x2c, -0xf6,0xa6,0x6a,0xf4,0x01,0xe5,0xb4,0xea,0xd2,0x9f,0xf4,0xf0,0x1a,0xb4,0x98,0x12,0xe4,0x58,0x93,0x34, -0xa7,0xb8,0x47,0xdd,0xa5,0x32,0x55,0xed,0xd3,0xc7,0x91,0xe6,0x9e,0xcc,0x2c,0xb1,0xe5,0xa4,0x0e,0x48, -0xb3,0x2f,0xd5,0x99,0x90,0xe6,0x80,0xe7,0x74,0x33,0x58,0xd0,0xed,0xa2,0x11,0x35,0x3c,0x20,0x5d,0xa8, -0x14,0xca,0x19,0x90,0xeb,0x52,0xd6,0x86,0x94,0x29,0x81,0xf1,0x5a,0xb4,0x53,0x2c,0x3f,0x52,0x0b,0x5e, -0xc1,0x03,0x69,0x16,0xff,0xfb,0xdb,0x7f,0xb9,0xff,0x35,0xdd,0xdb,0xdd,0xdb,0xfb,0xaf,0xc7,0x56,0xe9, -0x66,0xe5,0x67,0xe4,0xf9,0x1f,0xc5,0xa1,0x3a,0xc7,0x7a,0xf9,0xb1,0x9b,0x2f,0xaa,0x63,0xf8,0x99,0xcf, -0x7e,0xd3,0xf2,0xdf,0x6f,0x72,0xf0,0xe6,0x31,0x65,0x38,0x2f,0x1c,0x98,0x7e,0xda,0xa4,0x63,0x73,0x73, -0x8f,0xe1,0xae,0xf9,0xe3,0x96,0xa6,0xc9,0x35,0x46,0x60,0x58,0xc2,0xa2,0xf1,0x9c,0x29,0x66,0xcb,0x81, -0x57,0xa1,0x0a,0x5b,0x5a,0xf5,0x6c,0x6a,0x7f,0x24,0xec,0x30,0x19,0x24,0xd8,0x92,0x86,0x99,0x84,0xb6, -0xa1,0x02,0x55,0xcf,0x62,0x25,0xe4,0x63,0xa8,0x76,0x83,0xbc,0x2f,0x7d,0xc4,0x5f,0xdf,0xc8,0x0a,0xdd, -0x8e,0x62,0xc3,0xdd,0x34,0x58,0xd9,0xcd,0x93,0x8a,0x44,0xeb,0x7a,0x5a,0xff,0x2e,0xd4,0xa7,0xbf,0x1f, -0xc4,0xf6,0x8c,0x69,0x53,0x09,0x70,0x90,0xd8,0x52,0x62,0x07,0x9a,0xd0,0x0f,0x8c,0x4a,0x2c,0xf4,0xe9, -0xa1,0xdb,0xd4,0x1f,0x25,0x41,0xe9,0x9b,0x56,0x58,0x8f,0xc0,0x6c,0xc0,0xea,0x4d,0xaa,0x47,0x47,0xf4, -0x61,0xcb,0x72,0xf3,0x38,0x7c,0x08,0x45,0x3e,0x0a,0xe1,0xe7,0xff,0x5b,0x48,0xed,0x1c,0x74,0x4c,0xd9, -0x34,0x01,0x9b,0x91,0x9e,0x0d,0x92,0xbc,0x37,0x07,0x3d,0xd0,0x7d,0xfb,0xb4,0x1e,0xc8,0x7d,0xb6,0x84, -0xce,0xa6,0xb6,0xb0,0x4a,0x1e,0x1d,0x52,0x72,0x9f,0x80,0x5b,0x89,0x1a,0xe0,0x7f,0xaf,0x90,0x95,0x2c, -0x25,0x55,0xa3,0x14,0xe0,0x35,0x0c,0xa8,0xf5,0xa1,0x09,0x52,0xc7,0x7a,0xef,0x7d,0xfc,0x46,0x89,0x67, -0xdd,0xdc,0x80,0xab,0x88,0xdd,0x5b,0x7a,0xea,0x34,0x7d,0xc2,0x80,0x1e,0x8d,0xd1,0x90,0x11,0xbf,0xa1, -0x81,0x15,0x64,0x3b,0x5e,0x03,0x97,0x36,0xfc,0xab,0xa2,0x9c,0x04,0xcc,0xe1,0x23,0xfd,0xf5,0xa4,0xfa, -0x46,0x40,0x93,0x2d,0x2b,0xfe,0x20,0x0d,0x8a,0x73,0x92,0x52,0xca,0xc0,0xc8,0xf1,0x31,0x49,0xf5,0x26, -0x26,0xb5,0x34,0xcb,0x20,0xe9,0xfd,0x62,0x31,0x77,0x53,0x04,0xc6,0x32,0x3d,0xdb,0xc6,0xdd,0xf3,0xc0, -0x7e,0xd6,0x68,0xb8,0x53,0x0b,0x75,0xe6,0xf2,0xce,0xc0,0x7f,0x53,0x63,0x06,0x37,0xdb,0xa3,0x96,0xac, -0x52,0x8d,0xed,0x4a,0x83,0x71,0x03,0xc3,0x53,0xdd,0x01,0x4f,0x94,0xd0,0x6e,0x3e,0x9f,0xdb,0x74,0xdf, -0x4f,0x37,0x5d,0xe6,0x09,0xf2,0x1d,0x7e,0x12,0x1a,0x8a,0xd9,0xb4,0x1e,0x8b,0x45,0x59,0x4d,0x0d,0x37, -0xc3,0x1d,0x7a,0x58,0x44,0xd5,0x78,0x3c,0xc9,0xa4,0xea,0x8e,0x19,0xc3,0xa7,0xa6,0x66,0x58,0x3c,0x0e, -0xec,0xe0,0xc8,0x46,0x33,0xec,0x5a,0x60,0xc6,0xf0,0xc7,0x2c,0x4d,0x78,0x5b,0x2a,0x83,0xca,0xb3,0x96, -0x97,0xc3,0x15,0xac,0xdc,0x47,0x0b,0x89,0xda,0xa0,0xef,0x62,0x9d,0xd2,0xd7,0x68,0x42,0x02,0x04,0x52, -0xc6,0x10,0xc6,0x4d,0xa0,0xeb,0x86,0x6f,0xe1,0x21,0x44,0xb4,0x8e,0x23,0xef,0xfb,0xa9,0x52,0xf8,0x83, -0x1f,0x8b,0x68,0xf0,0x63,0x63,0xe0,0xbd,0x8c,0xc8,0x0a,0x0d,0x02,0x39,0x58,0x3e,0x06,0x2d,0xec,0x67, -0x51,0x14,0xff,0x6b,0x07,0xa4,0x1f,0x26,0x52,0x18,0xf4,0x8b,0x2e,0xf3,0x06,0x9a,0x82,0x54,0x0f,0xc9, -0x6c,0x1d,0x3d,0x91,0x86,0x8b,0xdb,0xb2,0xe5,0x70,0x42,0x0e,0x40,0x0f,0x88,0x93,0xb0,0xea,0x83,0xf3, -0x58,0x52,0xa2,0x2c,0xf6,0x23,0x0e,0x65,0xa5,0xc9,0xbd,0x25,0x3c,0xad,0x41,0x68,0xcc,0x9d,0x1d,0x57, -0xc3,0x26,0xc7,0x40,0x47,0xc7,0xe8,0x27,0xcb,0xb5,0xf0,0x41,0xb0,0x6c,0x70,0xa6,0x8b,0x9e,0xf0,0xf2, -0x53,0x8c,0x9a,0xe8,0x70,0x2f,0x41,0x5f,0xda,0x71,0x96,0xe4,0xa5,0x3d,0x46,0x92,0xa3,0x60,0x49,0xd4, -0x89,0x8f,0xa3,0x8a,0xc4,0xec,0xa5,0xec,0x12,0xe6,0xbf,0x7c,0x63,0xfc,0xaa,0xb0,0xfa,0x37,0xf4,0xd8, -0x02,0x11,0xe7,0x73,0xe8,0x26,0xbb,0x83,0x30,0xe5,0xa8,0x53,0xd6,0xf7,0x25,0x5a,0x46,0x5a,0xb4,0x18, -0x39,0xf7,0xe4,0x55,0xac,0xca,0x67,0xd8,0x44,0x8e,0xe4,0xcf,0x9f,0x42,0x77,0x5a,0x78,0xca,0x6b,0xc2, -0x81,0x95,0xf6,0x29,0xe2,0xc0,0x6e,0x4a,0xac,0xee,0x87,0x0a,0xfd,0x1c,0x54,0x15,0xbb,0x5e,0xa4,0x75, -0xf0,0x50,0x4c,0x23,0xb6,0x20,0xe9,0x81,0x9a,0x80,0xa6,0xa2,0xf4,0xe3,0x94,0x7c,0x0b,0x66,0x7e,0x13, -0x38,0xc0,0x0d,0x51,0x03,0x98,0xd5,0x4f,0x0d,0x0a,0x0d,0x6b,0x51,0x7e,0xf0,0xe3,0xc1,0x49,0x20,0x11, -0x9f,0x73,0xe7,0x44,0xcd,0x80,0x26,0xcf,0x04,0xbc,0x3c,0x26,0xa0,0xc6,0x73,0x31,0xf5,0x14,0x38,0x55, -0xe0,0xfc,0x52,0x67,0x02,0xe9,0xc0,0x92,0xfd,0xfc,0x14,0x6f,0xe3,0xbd,0x45,0x91,0xcf,0x72,0xa5,0xc0, -0xed,0x36,0x54,0xfc,0x07,0x31,0x0c,0xa8,0x02,0xa7,0x37,0xea,0xab,0xd3,0xf8,0x75,0x42,0x03,0x96,0x9d, -0x4a,0xcd,0xc4,0x20,0x81,0x47,0x05,0x96,0x1b,0x2f,0xc2,0x30,0xe0,0x17,0x3d,0x7f,0x69,0x32,0x0f,0x84, -0x9d,0xa0,0x19,0x6b,0x77,0x24,0x62,0x3b,0xc8,0x59,0x82,0x72,0x50,0xc5,0x5f,0x2c,0x30,0x43,0x2e,0x54, -0x60,0xa2,0x41,0x46,0xbe,0x15,0x3f,0x40,0x44,0x3e,0x82,0x9d,0xd0,0x20,0x39,0xd0,0x13,0x62,0xc7,0x14, -0x8d,0x76,0x0b,0x38,0xca,0x8a,0x8f,0x2a,0xa9,0x64,0x06,0xb8,0xf7,0x31,0x5f,0x6e,0x48,0xc7,0xf3,0x30, -0xc7,0x55,0xa5,0x83,0x45,0xa0,0x0d,0x72,0xfe,0x57,0x44,0x1e,0x0b,0xdf,0x7d,0xf6,0x29,0xe0,0xbc,0x87, -0x15,0x05,0x78,0x26,0x34,0xc4,0x40,0xb7,0x01,0x7c,0x04,0xf2,0x3a,0x4d,0xc0,0x31,0x30,0x0f,0xa0,0x28, -0x06,0x96,0xbc,0x8f,0x1c,0x3b,0x68,0x02,0xfa,0x61,0xc9,0x92,0x4e,0x9b,0x2c,0x79,0xf4,0x30,0x06,0xe6, -0x89,0x3a,0x40,0x60,0xd7,0x4f,0x19,0x27,0xf2,0x79,0x0c,0x23,0x6a,0xbf,0x04,0x01,0x7d,0xa6,0x05,0x71, -0x2f,0x96,0x85,0x4b,0x7c,0x8e,0x92,0xe6,0xa3,0xbd,0x37,0x68,0x88,0xdc,0x6e,0xe2,0x68,0x1a,0x68,0x15, -0x8c,0x29,0x33,0x1a,0x81,0x6f,0xe2,0x86,0x93,0xd4,0x03,0xcf,0xee,0xf9,0x06,0xc2,0xdd,0x94,0x92,0x30, -0xa9,0xe9,0x38,0x35,0xf4,0x46,0x59,0xa5,0x61,0xc8,0x44,0xf6,0x07,0xdc,0xd0,0x2c,0xf0,0x28,0x13,0xb0, -0x40,0x11,0xd5,0x7c,0x78,0x56,0x97,0x34,0xad,0x68,0x90,0x52,0xda,0x43,0x6f,0x0a,0x13,0xd4,0xd7,0xa5, -0x6a,0x25,0x27,0xa7,0x58,0x4b,0x4b,0x95,0xdb,0x5e,0xcc,0x3c,0xc1,0x4c,0x44,0xb6,0x99,0x1f,0xeb,0x21, -0x97,0x0b,0x72,0xad,0x89,0xfc,0x0f,0x55,0xf9,0x2c,0xd5,0x5a,0x35,0x50,0xe3,0xcc,0x1a,0x3b,0xe0,0xee, -0x60,0x52,0x83,0xea,0x4e,0x27,0x78,0xb6,0xba,0xa1,0x13,0x30,0x00,0x12,0x04,0x51,0x77,0x3e,0xee,0xd9, -0x26,0x53,0xdf,0x03,0xeb,0x1b,0x7b,0x2c,0x18,0x1e,0x7e,0x9d,0xc6,0x76,0x80,0xc1,0x48,0xac,0x2c,0xe7, -0x47,0x93,0x32,0x5b,0xcc,0x5e,0x51,0xd8,0x61,0x34,0x85,0x39,0x2e,0x8a,0x40,0x88,0x42,0xd7,0x86,0x82, -0xb0,0x28,0x1d,0x32,0xdc,0x7d,0x9c,0x70,0xb9,0xcf,0xd4,0x23,0x1f,0x3b,0x23,0x7b,0xa5,0x61,0x82,0x80, -0x8c,0xf4,0x35,0x46,0x66,0xc5,0xc3,0x68,0xdf,0x4d,0xec,0x68,0x30,0x8b,0xd9,0xf5,0x64,0xcf,0x44,0x0a, -0x89,0x79,0xa9,0x71,0x04,0xb5,0x8f,0x69,0x0a,0x28,0xce,0xc2,0x69,0x7c,0x23,0x58,0xaf,0x41,0x4e,0x75, -0x63,0x03,0x99,0x41,0x9c,0x91,0x8b,0x85,0xc4,0x40,0xba,0xa3,0x5e,0xc3,0x34,0xc8,0xd1,0xf2,0xf2,0x06, -0xfb,0x87,0xa6,0xa5,0x8f,0x04,0x2f,0x58,0xd8,0xc1,0x12,0xda,0x23,0x59,0xec,0x38,0x34,0x18,0xd0,0xbc, -0xf1,0x0f,0x94,0x9e,0x07,0xcb,0xcb,0x87,0xb8,0xa1,0x4e,0x8f,0x8c,0x1f,0xa8,0x27,0x6c,0x03,0xbf,0xcc, -0xfb,0xcd,0x4e,0x9b,0x73,0x9e,0x49,0x06,0x3c,0xc6,0x12,0x05,0xf0,0x3c,0x0a,0xad,0xb4,0xd1,0xc4,0xc1, -0x68,0x80,0x06,0x2d,0x3b,0xe9,0x48,0xd3,0xd6,0xbc,0xad,0x63,0x0e,0x41,0x08,0x12,0xad,0x00,0x7c,0xd3, -0x6c,0xfa,0x7b,0x16,0xfc,0x0c,0x06,0x1e,0xdb,0x78,0x12,0x61,0x86,0x09,0x35,0x12,0x27,0x09,0x5d,0x2d, -0x2f,0xb7,0x41,0x82,0xd1,0x9c,0xc5,0x67,0xfa,0xf9,0x41,0xa3,0x4a,0x95,0x1b,0xf1,0xfe,0x33,0xe7,0x73, -0x70,0x4e,0x92,0x4f,0x5d,0x51,0x89,0x8a,0x10,0xd2,0xc9,0x55,0xf1,0x30,0xf2,0x79,0xb8,0xe6,0x36,0x46, -0xb3,0xd9,0xd1,0x71,0x2f,0xe5,0xcd,0xb3,0xa3,0xf9,0x35,0x71,0x36,0x00,0x2a,0x8c,0x77,0x5e,0xb8,0x77, -0xc1,0xce,0x5e,0xba,0x00,0x07,0x11,0x98,0x10,0x83,0x3b,0x4b,0xa7,0x40,0xd7,0x53,0x11,0xe6,0xe6,0xc4, -0xa0,0x44,0x05,0x96,0xc1,0xe8,0x53,0x10,0x91,0x09,0xe2,0xd6,0x69,0xb9,0xe8,0x4c,0xec,0x66,0x5d,0x46, -0x1b,0x29,0x3a,0x6f,0xe8,0x19,0x50,0x3c,0x6e,0xd3,0xf5,0xd5,0xd9,0x8c,0xa8,0xe7,0x04,0x8f,0x1b,0xbb, -0xd1,0x8a,0x20,0x44,0xaf,0x30,0x5d,0xa1,0xcb,0xd2,0xd3,0x4c,0x3f,0xa5,0x07,0xd3,0x1c,0x4d,0x7a,0xe8, -0xee,0x5d,0x66,0xc5,0xa5,0x51,0x1c,0x30,0x87,0xa9,0x84,0xc6,0xdd,0x20,0xb6,0x81,0xa0,0x66,0xf0,0xc8, -0xd6,0xd8,0x3f,0xad,0xbb,0xbc,0x8c,0x5a,0x39,0x48,0xaa,0x05,0xd3,0xcb,0x43,0x54,0xf4,0x73,0xd2,0x31, -0x9a,0x00,0x87,0x93,0xf8,0x09,0xb7,0x3e,0xc5,0x1e,0x0b,0xd7,0x0c,0xc1,0xaa,0x1d,0xe0,0x6e,0x9f,0x39, -0xff,0x81,0x3e,0xc6,0x15,0xd2,0x27,0x76,0xb6,0x01,0x67,0xeb,0x07,0x64,0xf0,0x5c,0x83,0x3f,0x6b,0x17, -0x94,0xf8,0x3f,0xca,0x78,0xb0,0x32,0x12,0xc6,0x47,0x31,0x19,0x84,0x04,0xb3,0x56,0x70,0x8e,0x1f,0x3d, -0x6e,0x1a,0x12,0xc7,0x09,0xe7,0x3e,0x6c,0x83,0xa8,0xec,0x8f,0xc8,0x21,0xcf,0x24,0xf7,0x77,0xa7,0x3d, -0x11,0x50,0xbb,0x01,0xb3,0x83,0xd6,0x05,0x87,0x80,0x05,0x7d,0x9a,0x81,0x45,0x20,0x85,0x73,0x1d,0xd9, -0x88,0xfa,0x76,0x45,0x63,0xe7,0xd2,0x6b,0x23,0x30,0xa0,0x0f,0xa2,0x27,0xce,0xc4,0xfd,0xf6,0x99,0xdc, -0x66,0x80,0xc4,0xa5,0x25,0x12,0x84,0xb5,0x2c,0xf9,0xec,0x12,0xc7,0x97,0x17,0xca,0x8e,0x5e,0x74,0xb2, -0xd4,0xfb,0xff,0x99,0x7b,0xd7,0xf5,0xb6,0x8d,0x64,0x6d,0xf4,0xff,0x77,0x15,0x12,0xe2,0x51,0x00,0x13, -0xa2,0x28,0xe7,0x30,0x13,0x50,0x30,0x97,0xe3,0x43,0xec,0x19,0x3b,0xf6,0xd8,0xce,0x69,0x28,0x26,0x1f, -0x24,0x42,0x12,0x12,0x0a,0x60,0x00,0xd0,0x92,0x23,0x72,0xee,0x6c,0x3f,0xfb,0x92,0xf6,0x2d,0xec,0x7a, -0xab,0xba,0x1b,0xdd,0x00,0x28,0x7b,0xb2,0xbe,0xf5,0xec,0xed,0x27,0x11,0x71,0x68,0xf4,0xb9,0xab,0xab, -0xeb,0xf0,0x56,0x8c,0x4d,0xce,0xd2,0x00,0x14,0x6d,0xa6,0x21,0xd5,0x94,0x74,0xed,0xb1,0xa6,0xda,0xf0, -0x0c,0x98,0x23,0x0f,0x87,0x09,0x8d,0xc5,0x53,0x76,0xed,0x98,0xe6,0xc4,0x36,0x10,0x25,0xed,0x80,0x01, -0x28,0x76,0x89,0x0e,0x12,0xf8,0xbe,0x6b,0xc3,0xe3,0xfa,0x9b,0x40,0xc6,0x59,0x15,0xab,0xf2,0x34,0x7d, -0x06,0x59,0xd7,0x7e,0x6d,0xdf,0x89,0x3c,0x5a,0xef,0x87,0x4c,0x44,0x45,0x3d,0x42,0xb4,0x74,0x98,0xd3, -0x21,0xec,0x4d,0x76,0xb2,0x20,0x5a,0xca,0x22,0xd6,0x9c,0x8f,0x19,0x92,0x78,0xff,0xd0,0x8c,0xcb,0xe4, -0x30,0xda,0xb7,0xdc,0xbc,0xaa,0x5e,0xad,0xce,0x07,0x5d,0x41,0xd4,0xc1,0xca,0x76,0x08,0xa9,0xc5,0x0d, -0x87,0x1a,0x67,0xf5,0xe7,0xea,0xbf,0x93,0xbd,0x6f,0xe5,0x4f,0xcc,0xbc,0x42,0xef,0xc4,0x5d,0xb0,0xa5, -0xb8,0xc5,0x96,0xe2,0xf4,0x39,0xb0,0x28,0x2f,0xd9,0x98,0x6e,0xd2,0x9e,0x22,0x2a,0x02,0xf4,0x9c,0x79, -0xe8,0x89,0xc7,0x30,0x36,0x92,0xd2,0xba,0xb6,0xbe,0x71,0x32,0xb0,0xbf,0x4e,0xa3,0xba,0x7d,0x9b,0x55, -0x8f,0xac,0x07,0xd0,0x3c,0x34,0x4f,0xc0,0xe4,0x53,0x05,0x1e,0x63,0x46,0xf7,0x7d,0x6d,0x95,0xde,0xaa, -0xa6,0xdd,0xec,0x53,0xab,0xd9,0xa5,0xdf,0x6d,0x38,0x2d,0xad,0x41,0x1d,0x5a,0x6f,0x44,0xc5,0xa5,0x26, -0x39,0x2c,0x44,0x52,0xb0,0x72,0x7a,0x72,0xc3,0x86,0x01,0x0e,0x26,0x9a,0x9d,0xc4,0x54,0xcf,0xa7,0x30, -0x7f,0x49,0x66,0x22,0xa6,0xcf,0x68,0x11,0xfb,0x25,0x7e,0x70,0x1d,0xb0,0xdd,0x9d,0x8d,0xca,0x60,0x2d, -0xf8,0xbd,0xbd,0x8f,0x77,0x1e,0xa6,0xc9,0xef,0xc2,0x2e,0xb4,0x70,0x15,0x1a,0x13,0x93,0x51,0xd8,0x9c, -0xa0,0x68,0x59,0x79,0xde,0xb8,0x26,0x26,0xbe,0x06,0x8f,0x3d,0x60,0x7e,0x72,0xc8,0xb0,0x78,0x46,0xe3, -0xb4,0x0d,0x39,0x21,0x46,0x9f,0xb2,0x87,0x06,0xaf,0x1f,0xea,0x89,0x6c,0xbd,0x86,0xe9,0x09,0x1c,0x96, -0x9a,0x11,0x66,0xad,0x01,0x6d,0x17,0xbf,0x0c,0x06,0x8d,0x78,0x92,0xe5,0x78,0x0d,0x48,0x01,0x08,0xad, -0x72,0xfb,0x1d,0xd7,0x72,0x88,0x08,0x3a,0xee,0x64,0xeb,0x75,0x62,0x6c,0xe5,0xd5,0x17,0x63,0x43,0xbf, -0x1c,0x9b,0x8c,0x70,0xa5,0x54,0x88,0x30,0x0b,0x85,0x6f,0xf0,0xd7,0x61,0x35,0x13,0x17,0x9a,0x4e,0x19, -0x3d,0x85,0x50,0x57,0xaa,0x5c,0xf4,0xb1,0x7b,0xb4,0x31,0xec,0xfe,0xed,0xf5,0xa3,0x87,0x67,0xf4,0xfe, -0x07,0xb8,0xb1,0xe3,0x87,0xe5,0x5c,0xa7,0xf1,0x19,0x51,0xfe,0x55,0x9e,0xd1,0xae,0xf5,0xec,0x11,0x5e, -0x39,0xf7,0x9c,0x06,0x0e,0xb0,0xf1,0x2d,0x7b,0xb6,0x94,0x4a,0x0b,0x60,0xac,0x99,0x19,0x7f,0x11,0x9f, -0x62,0x5b,0xdd,0xdb,0x5b,0xc0,0x47,0x2a,0x8e,0xbf,0xc6,0x15,0x2b,0x51,0x2a,0xdd,0x4f,0x4b,0x62,0x78, -0xe2,0x05,0xfd,0x11,0x5d,0x14,0xed,0xca,0xcb,0x90,0x9f,0x75,0x1b,0x68,0x7a,0xd2,0x41,0x98,0xb0,0x8e, -0x05,0x32,0x61,0xee,0x1f,0xba,0xa3,0x66,0xaf,0x05,0xeb,0x5c,0xae,0x9c,0x1d,0x76,0x71,0xb8,0x56,0xe9, -0x7a,0x44,0x18,0x11,0xdc,0x27,0x1c,0x10,0x85,0x76,0x8e,0x50,0x7b,0xe7,0xcd,0x69,0xbf,0xe0,0x33,0x3d, -0x78,0x68,0xac,0x9d,0x46,0x35,0x6c,0x4f,0xd2,0xf7,0x5b,0x1c,0xc9,0x71,0xc0,0xac,0xd8,0x2c,0x2a,0x6d, -0x04,0x9d,0x72,0x4e,0xab,0x8d,0xd8,0x91,0x4d,0xdc,0xab,0x59,0x20,0x8e,0x41,0xbb,0x39,0x1c,0x94,0x29, -0x1f,0x76,0x22,0x55,0x07,0x39,0xb8,0x15,0xab,0xdd,0xbe,0xea,0x37,0xe2,0xbf,0x54,0x35,0x60,0xe6,0xbe, -0x51,0x19,0x40,0x6a,0x45,0x53,0x82,0xad,0xe1,0x2e,0x99,0xdd,0xa3,0xf3,0xe1,0x6e,0x21,0x8f,0x8a,0x18, -0x4e,0x65,0x09,0xec,0x4f,0x1a,0x52,0x53,0xca,0xd9,0xa0,0x35,0x99,0xe1,0xe8,0x4e,0x7f,0x2e,0xe0,0xd6, -0x2d,0xed,0x38,0x87,0xe3,0xef,0x3b,0xe5,0xe5,0x1f,0x56,0x96,0xe3,0x7a,0x35,0x8b,0xaa,0x70,0x4a,0x47, -0xa4,0xcb,0x18,0xe7,0x02,0xb0,0xfd,0xf5,0xe4,0x3c,0x7a,0xef,0x9f,0x87,0xcb,0x30,0xe5,0xcc,0xc3,0xeb, -0x38,0x9f,0x14,0xd0,0x38,0x4f,0xd2,0xe8,0x02,0xde,0x6e,0x93,0xe9,0x2c,0x4a,0xa2,0x4b,0xde,0x23,0xf7, -0xf6,0x72,0xff,0x32,0xbc,0x96,0x94,0x19,0xef,0x98,0x8b,0xf8,0xbd,0x7f,0x1d,0xce,0x59,0x99,0x1e,0xa2, -0x53,0xf1,0xea,0xb4,0x61,0x01,0xd9,0xe9,0x9c,0x96,0xc1,0x62,0x7a,0xca,0x1d,0x79,0x3d,0x9d,0xd3,0x15, -0xa8,0xde,0xa5,0xba,0x3a,0xd3,0xea,0x61,0xcc,0xe3,0x02,0x3e,0x2b,0x7c,0x21,0xc3,0xb5,0x88,0x19,0xfc, -0xe3,0xba,0x9d,0xdd,0xb5,0x64,0xb7,0x90,0xae,0xbf,0xa4,0x3b,0xca,0x67,0x5c,0xb0,0x98,0x98,0xda,0x30, -0x85,0xa3,0xdc,0x8a,0x28,0x29,0xfb,0xc8,0x6d,0xfb,0x9a,0x72,0x2f,0x26,0x69,0x4a,0x3d,0x7b,0x16,0x44, -0x4b,0x3c,0xbb,0xbf,0x7f,0x08,0xd1,0xcb,0x74,0x81,0x0a,0x26,0xf8,0x39,0x83,0x3d,0x24,0xaf,0xf7,0x6b, -0xb4,0x34,0x86,0x17,0xd2,0xb5,0x12,0xbc,0xfb,0x17,0xa1,0xce,0x3a,0x88,0xae,0x69,0x04,0x27,0xaa,0x02, -0x09,0xf5,0xd1,0x2a,0x88,0x34,0x8f,0x4a,0xb7,0x0e,0x59,0xbf,0x76,0x48,0xb0,0xcc,0xce,0x66,0x1e,0x16, -0xf1,0xc3,0x21,0x20,0x45,0xe1,0x23,0x3e,0x15,0x97,0x22,0x1a,0xbd,0x19,0x36,0x92,0xf5,0xda,0x7a,0x05, -0x7e,0x91,0xe6,0x70,0x01,0x4b,0x7f,0x9a,0xc7,0x96,0xef,0x64,0x0b,0x13,0x6a,0x43,0xf5,0x11,0x73,0xe2, -0xfe,0x34,0xa9,0x46,0x65,0xd2,0x09,0x4f,0xe3,0xa9,0x75,0xd4,0x6d,0x8e,0xa7,0xf1,0x2e,0x14,0xb2,0x70, -0x2b,0xa7,0xdd,0xf6,0x57,0xac,0x03,0x80,0x95,0x04,0xcd,0x0c,0x5b,0xa9,0xe4,0xd1,0x42,0x5d,0x34,0xba, -0x92,0x58,0x30,0x3d,0x36,0x33,0x5a,0x5d,0x99,0x11,0xea,0xbb,0x4d,0xad,0x54,0x53,0x03,0xaa,0x00,0x31, -0xee,0xc4,0xc6,0xd3,0xf6,0x32,0x33,0x34,0x0e,0xa9,0xc5,0x12,0xcc,0x4a,0xab,0x8f,0x01,0xc8,0x9d,0x9f, -0xb2,0x1d,0x0c,0x20,0x0c,0x72,0x5a,0x4b,0xd2,0xcd,0x65,0x3c,0x18,0x54,0xe3,0xf2,0x08,0x8b,0xce,0x29, -0xb0,0x54,0x99,0xb0,0xd0,0x4a,0x57,0xf5,0xd2,0xaf,0xe0,0xc6,0xca,0xc5,0xf3,0x15,0xed,0x98,0x4a,0x8b, -0x3f,0x0a,0xab,0xfd,0x43,0xe3,0xd0,0x70,0xc3,0x3b,0x63,0x44,0xe3,0x00,0x2e,0x62,0x5a,0xed,0xdf,0x93, -0xec,0x26,0xb4,0xee,0x22,0xcf,0xdb,0x58,0x22,0x7a,0x73,0x88,0xc8,0xc3,0xea,0xa8,0x84,0x13,0xa1,0xce, -0xb2,0x12,0x33,0x33,0xd4,0xed,0x1a,0x40,0x57,0x0d,0x74,0x93,0x3c,0x9c,0xb3,0x24,0xfb,0xd4,0xd8,0xd8, -0x68,0x35,0x1d,0xd5,0xce,0x85,0xcb,0xd0,0x62,0x2d,0x43,0x21,0xef,0x83,0x5c,0xa6,0xcd,0x4d,0x12,0xb7, -0x49,0x49,0xb8,0x90,0x6f,0x98,0x94,0x28,0xc0,0x0c,0x6f,0xe4,0x81,0x82,0xec,0xed,0x01,0x1d,0x04,0xeb, -0xe8,0x32,0xfe,0x95,0x16,0x14,0x0d,0x3a,0x8d,0x3d,0xfa,0x3f,0x9f,0x0f,0xdf,0x3e,0xf8,0x06,0xca,0x7e, -0x18,0xb5,0x9d,0xc4,0x5f,0x0f,0x62,0x11,0x24,0x5e,0xd2,0x44,0x74,0x34,0x14,0xeb,0xf5,0xf0,0x30,0xbc, -0x6a,0x56,0x1f,0xaf,0x67,0x9a,0x40,0xbf,0xc6,0xd0,0xd9,0x3f,0x65,0x7b,0x9d,0x45,0x30,0xbe,0xa0,0xc9, -0x74,0xa5,0x2d,0xb1,0xb0,0x5a,0xa7,0x17,0x74,0x3c,0xbc,0xa0,0x11,0x61,0x3a,0xb0,0xb7,0x77,0x2a,0xa3, -0x08,0x8f,0x64,0xfa,0xe2,0xd4,0x15,0x52,0x48,0x4e,0xfe,0x73,0x1e,0xad,0x78,0xf7,0x65,0x30,0x5e,0xd2, -0x58,0x9c,0x69,0x80,0x09,0x58,0xec,0x25,0x10,0x5a,0x54,0x6c,0x5d,0xc2,0xbd,0x78,0xaa,0x4d,0x00,0x50, -0x99,0xaf,0xe3,0x93,0x60,0x03,0x24,0x03,0x2a,0x79,0x77,0x89,0xc2,0xa8,0xcf,0xf7,0xf7,0x81,0xf7,0x73, -0xae,0x93,0xb3,0x93,0xc1,0x7c,0x10,0x5f,0x60,0x63,0x46,0x75,0xe7,0xa6,0x46,0x54,0x5a,0xae,0x4a,0x5b, -0x12,0x19,0x7d,0x87,0x8e,0xb5,0xc8,0xd9,0xfc,0xfe,0x48,0xce,0x15,0x17,0xa0,0x3c,0xe7,0xd4,0x32,0x22, -0xcd,0xfc,0xd7,0xc7,0x4f,0xfc,0x4f,0x91,0xa2,0xd1,0xd6,0x3b,0x7e,0x47,0xe4,0xe5,0x5d,0xb0,0xd1,0x34, -0x63,0x15,0xbe,0xe3,0xcd,0x05,0x44,0xfa,0x9d,0x19,0x44,0xaa,0xdb,0xc0,0x8c,0xef,0x21,0xb6,0x1e,0x61, -0x1c,0xde,0x14,0x65,0x4d,0xb9,0xe8,0xd9,0xa1,0x1a,0x16,0xfe,0x1a,0x5f,0x06,0xe1,0xb9,0x81,0x41,0xcb, -0x26,0xa5,0x9f,0x04,0x51,0xc2,0x67,0xcc,0xab,0xf0,0x6d,0xf8,0x30,0x7c,0x1c,0xfe,0x16,0xbe,0x09,0xbf, -0x0d,0x1f,0x85,0xbf,0x86,0x0f,0xc2,0xdf,0xc3,0xe7,0xe1,0xd3,0xf0,0x49,0xf8,0x32,0x7c,0x15,0xbe,0x0e, -0x5f,0x84,0xcf,0xc2,0x1f,0x62,0xaf,0xca,0xfe,0xf8,0x63,0x91,0x7a,0x83,0xc3,0xbb,0xd0,0x1d,0x41,0x5e, -0x16,0xde,0xb1,0xad,0x11,0xbe,0xa6,0x71,0xf9,0x85,0xfe,0xff,0x23,0xa6,0x13,0x71,0xf8,0x23,0xff,0xfd, -0x8e,0xff,0x7e,0xdf,0xaf,0x8f,0x67,0xa2,0x44,0x35,0xfc,0x1d,0xc6,0x17,0xe1,0x68,0x13,0x7e,0x43,0x4c, -0x4f,0xdb,0xdc,0xe0,0x27,0xcc,0xbd,0x7f,0xc6,0x3f,0x0d,0x97,0xc5,0x32,0xfc,0x3b,0x7e,0x61,0xbc,0xf0, -0x0f,0x7d,0xf1,0x2f,0xba,0x10,0x3b,0x87,0xb4,0xad,0xf5,0xff,0x00,0x36,0x0d,0x6c,0x66,0x60,0x48,0xd5, -0x9c,0xe9,0x0c,0x3e,0x0f,0x28,0x60,0xad,0xf1,0xfb,0xd3,0xf9,0x5a,0x40,0x9f,0xe9,0x22,0x01,0x1c,0xf5, -0x1a,0xce,0x6f,0x67,0xd4,0xea,0x8a,0xaf,0xd8,0x1f,0x43,0x05,0xdd,0xab,0xd6,0x73,0xd8,0x7e,0xaf,0xf5, -0xa9,0x62,0x2d,0x26,0xff,0xeb,0xac,0xba,0x4c,0x96,0xeb,0x45,0x51,0x2c,0xd7,0x1c,0xc1,0x73,0xb9,0x48, -0xd7,0xd4,0xbe,0x7c,0xad,0x21,0x35,0xd7,0x3a,0x76,0xd0,0xba,0x3a,0xa5,0x17,0x73,0x0f,0x96,0x1e,0xde, -0xf4,0xf8,0xf8,0xfa,0xde,0xe8,0xf8,0xb8,0x3e,0x3e,0x2e,0x8f,0x8f,0xf3,0xe3,0xe3,0xb3,0x99,0x07,0xa3, -0x0f,0xcf,0x9f,0x44,0xc7,0xf4,0x6f,0xb8,0xa6,0x14,0x57,0xfb,0xb3,0xf5,0xf4,0xe7,0xe3,0xd1,0x3e,0x25, -0x4e,0x46,0xb3,0x60,0xe0,0xc1,0xfc,0xc3,0x3b,0x3e,0x9e,0x7a,0x83,0x3c,0x1d,0x78,0x77,0x7d,0x6f,0x50, -0xd2,0x6f,0x40,0x1f,0xe9,0x27,0xd3,0xbb,0x3f,0xdf,0x59,0xef,0xfe,0x7b,0x36,0x89,0x03,0xfd,0x68,0x12, -0x7d,0xea,0x37,0xd9,0xfe,0x8c,0xdf,0x4f,0x67,0xc1,0xdd,0xe0,0xd3,0xf5,0xb1,0xd7,0x7e,0x71,0xec,0xe1, -0xcd,0xb1,0xb7,0xd6,0x59,0x07,0x6b,0x9d,0xcf,0xf1,0x31,0x55,0xb1,0xa0,0xf2,0x23,0xab,0xd8,0xe3,0x63, -0xdf,0xf7,0xff,0xf3,0xec,0x83,0x75,0xfb,0x8d,0x1f,0x50,0x83,0x67,0xb3,0xb5,0x37,0xc8,0x90,0xf5,0xdd, -0x60,0x3d,0xa4,0x84,0xc7,0x28,0x1e,0xa6,0x2d,0x98,0x97,0x22,0xc2,0xf5,0x51,0x19,0xea,0x09,0xef,0x1c, -0x46,0x44,0xce,0x1b,0xef,0x67,0xa9,0xea,0x80,0x73,0xff,0x59,0xe5,0x3c,0x0b,0x74,0x51,0x94,0xab,0x4a, -0x70,0x47,0x7d,0xbf,0xea,0xfd,0xfe,0x6e,0xa8,0x7e,0x81,0x29,0xd3,0x9f,0xc2,0x9f,0xde,0x1f,0xfc,0x1b, -0xb5,0xc5,0x5d,0xd0,0x24,0x3f,0x75,0x93,0xc7,0x26,0x39,0x55,0x65,0xf6,0x29,0x35,0xff,0xee,0xc4,0xe9, -0x4f,0xae,0xc5,0x99,0xf3,0x51,0x91,0x06,0x30,0xbd,0x69,0x95,0x8a,0x0e,0xbf,0xe3,0x89,0x05,0xce,0xb3, -0x47,0x91,0xf3,0xf6,0x13,0x3d,0x20,0xf4,0xfe,0xe1,0xf3,0x07,0x6f,0xde,0xb8,0xaf,0xa9,0xe5,0x56,0x02, -0xa2,0xec,0xee,0x6b,0xf5,0x6e,0x3d,0xbd,0x3b,0xc3,0xfb,0x07,0x6f,0xdf,0xbe,0x8e,0x5a,0x85,0x67,0x54, -0xa5,0x57,0x6f,0x1e,0x7f,0xf7,0xe8,0x65,0xfb,0x0d,0x2a,0xfb,0xf0,0xe9,0xb3,0xe7,0xad,0x1a,0x45,0x3e, -0x4f,0x7d,0x3e,0xf5,0xad,0x61,0x9f,0xb1,0xce,0xeb,0x0b,0xfc,0xbf,0x8f,0x9b,0x60,0xdf,0x67,0xf8,0x85, -0x75,0x71,0xb6,0xcf,0x80,0x18,0x32,0x91,0x74,0x5f,0x01,0xbf,0x63,0x5d,0xcc,0xe7,0x34,0x8a,0xd3,0x01, -0x2d,0x81,0xc0,0x3f,0x3e,0x9e,0xdf,0x0d,0xf2,0xb5,0x35,0xa3,0xd5,0x1b,0xfd,0x80,0x12,0x0c,0x68,0xaa, -0x34,0x5d,0xcb,0xf3,0xc6,0xcb,0xa8,0x3d,0x30,0x69,0x68,0x35,0x18,0xab,0xa5,0x46,0x77,0xdc,0x51,0x69, -0xf2,0x34,0x9d,0x57,0x6c,0xcf,0x78,0x5d,0xb7,0x5b,0xc8,0x19,0xca,0x68,0x47,0x4d,0xd5,0xd2,0xdf,0xd7, -0xe7,0xd4,0x32,0x69,0x57,0xd3,0xcc,0x56,0x4b,0xe8,0x8e,0xd6,0xee,0x3c,0x98,0x70,0x03,0xec,0xca,0xf9, -0x93,0x78,0xfa,0x33,0xb5,0xe0,0x8e,0xaa,0x26,0x1b,0x55,0x1d,0xa0,0x6a,0x2c,0xc6,0x51,0x74,0x69,0xad, -0x61,0x40,0xd6,0x22,0xcf,0x09,0xee,0x1c,0x64,0x30,0xb9,0x3a,0xf8,0xf9,0xe2,0x78,0x8e,0x6b,0xb1,0xa8, -0xfa,0xf9,0x66,0x36,0x38,0xbe,0x39,0xae,0xee,0x1e,0x4f,0x73,0xe6,0x7b,0x76,0x8e,0xaf,0x0e,0xc4,0x8a, -0x8a,0x32,0xfc,0xc4,0x9f,0x82,0x92,0x50,0xff,0xf8,0xc7,0x57,0xf4,0x97,0x66,0x83,0x7a,0x40,0xd9,0xb1, -0x81,0xd5,0x94,0x1a,0x77,0x00,0xdb,0x2a,0xbb,0xe9,0xbc,0x28,0x69,0x4d,0xce,0x93,0xfd,0xb3,0xd9,0xcd, -0x61,0xf8,0xe5,0x46,0xea,0x3f,0x59,0xab,0xe6,0xd1,0x0a,0xe5,0xca,0x63,0x06,0x9f,0xb8,0x14,0xba,0x11, -0x19,0x78,0xa3,0x6b,0xea,0xeb,0xfd,0x2f,0xbf,0xf8,0xe2,0xb3,0x2f,0xcd,0xd9,0x0d,0xe6,0x11,0xc4,0x61, -0x4e,0xea,0xa8,0x3c,0x1a,0x4d,0x44,0x69,0x33,0x84,0xf1,0xdc,0xc3,0x8b,0xa4,0x7c,0x08,0x78,0xa9,0x72, -0xc0,0x5f,0x04,0x51,0xef,0xcb,0xfb,0xf7,0x0f,0x47,0xeb,0x2f,0xbe,0xb8,0xf7,0xd5,0x97,0xe1,0xe1,0xe8, -0xde,0x67,0x7b,0xe5,0xfa,0x8b,0x2f,0x3f,0xbb,0x07,0x53,0xa0,0x2b,0x6a,0x0d,0x55,0x9a,0x28,0xe6,0xf5, -0xe1,0xd9,0xf1,0xf5,0x5f,0xcf,0x66,0xeb,0x9f,0xf7,0x27,0x34,0x02,0xf4,0x73,0x47,0xd1,0x52,0xf5,0x66, -0xff,0x78,0xf5,0x84,0xfe,0xa1,0x27,0x0e,0xce,0xc3,0xb7,0xdb,0x0c,0xcb,0x26,0xde,0xf1,0x48,0xd0,0x27, -0xbd,0xff,0xe7,0xff,0xfe,0xbf,0xbc,0xa8,0xe1,0x13,0x89,0x4d,0x1c,0x50,0x2f,0x01,0x89,0xe7,0x54,0x55, -0xed,0x01,0x20,0x5e,0x34,0x54,0x47,0x60,0x2c,0xe9,0xfc,0xc3,0x2f,0x03,0xc8,0x7e,0x23,0x49,0xbe,0x09, -0x1f,0x3a,0x3e,0xa0,0xcf,0x61,0x06,0xf4,0x38,0xdd,0xc2,0xba,0x3b,0xe2,0x36,0xd8,0x3c,0x1a,0xc9,0x1c, -0x34,0xfb,0x46,0xe4,0x05,0x8d,0xfa,0xcd,0x3c,0x2b,0x23,0x5b,0x12,0x13,0x42,0x4e,0x13,0x79,0x12,0xe2, -0x85,0xb8,0x55,0x16,0x0c,0x6b,0xf6,0xe3,0xa7,0xf8,0x5f,0xc2,0x9a,0xdc,0x71,0x60,0xc1,0xdc,0xbb,0x9f, -0xa6,0x77,0xba,0x50,0x29,0xb3,0x06,0xd0,0x55,0x04,0xcb,0xbf,0x51,0x7d,0xff,0x11,0xdf,0x70,0xbe,0xd1, -0x4f,0x2a,0xd5,0xc4,0xed,0xd0,0xbf,0xab,0x62,0xd3,0x50,0x15,0x5b,0x07,0x36,0x36,0x65,0x47,0x94,0xdc, -0xa8,0x9f,0xc7,0x10,0x9d,0x8b,0xae,0x99,0xb9,0xb0,0xb1,0x51,0x34,0x63,0x3b,0xdf,0x6c,0xde,0xc6,0xf5, -0x50,0xa9,0x19,0x61,0x9d,0xf8,0x5b,0x0c,0xa1,0xe1,0x8f,0x2f,0x9e,0x3b,0x0a,0x39,0xe5,0xe7,0x00,0xf7, -0xb3,0xb6,0x0a,0x8c,0x81,0x59,0xe5,0x46,0x49,0xd9,0xb4,0xc4,0x62,0x97,0x78,0x18,0x0f,0xe8,0x6b,0xae, -0x7a,0x65,0x13,0x3e,0x8f,0x59,0x45,0x62,0x38,0xd4,0x1e,0xbb,0x13,0x30,0x26,0x93,0x6e,0x59,0xd1,0x1d, -0x7b,0x19,0x3c,0xdd,0xdb,0xfb,0x2a,0xb6,0x11,0x4c,0xf6,0xf6,0xca,0x76,0x65,0x26,0xfe,0xd3,0xb8,0x0c, -0x9f,0xc4,0x4f,0xdb,0x2f,0xc2,0x97,0xf1,0xee,0x6f,0xfe,0x53,0x1a,0x32,0xc9,0x89,0x4e,0x4f,0x4f,0x0d, -0x2e,0x50,0x96,0x5e,0x31,0xc0,0x19,0x71,0x31,0x0a,0xa7,0x20,0x07,0x24,0x92,0x83,0xe5,0x3a,0xe9,0x3e, -0x02,0x0a,0xb5,0x00,0xbc,0x3e,0x4c,0x61,0x37,0x1f,0xe5,0x10,0xdb,0x27,0xa7,0x17,0x9c,0x0a,0x19,0x5a, -0xb7,0xbe,0x57,0xe4,0x4d,0x72,0x3a,0xce,0xbc,0x65,0x19,0x3f,0xeb,0x5b,0xaa,0x38,0xeb,0x9f,0xce,0xa7, -0x5a,0x01,0x16,0x13,0xdd,0x0b,0x77,0x7b,0x3d,0x46,0xf0,0xda,0x83,0xcd,0xfe,0xdb,0x5e,0xd1,0xe7,0xb6, -0xac,0x6d,0x60,0x38,0xad,0x1e,0x79,0x58,0x5c,0x8a,0x7a,0x04,0x6e,0xa8,0xbb,0x5b,0x00,0x17,0xb1,0x75, -0xab,0x39,0xd5,0x2d,0xd4,0x68,0xec,0xe2,0x77,0x4a,0x7f,0xf5,0x74,0x9b,0xf2,0x4f,0x3e,0x85,0xae,0xb2, -0xbf,0x8a,0x4f,0x9c,0x2a,0xd2,0xbc,0xcb,0xe6,0xf1,0x0f,0xe1,0x6e,0x2b,0x3f,0x64,0xb5,0x5e,0xf7,0x3d, -0x45,0x6c,0x7a,0xb7,0x9a,0x28,0x6b,0xe2,0xeb,0x43,0xf3,0xf0,0xd9,0xa3,0xbe,0x49,0x6f,0xce,0xa8,0xd7, -0x29,0x51,0xea,0x06,0xec,0xae,0xaf,0x0f,0xbb,0x1a,0x42,0x96,0x2f,0x10,0xcd,0x92,0x83,0xa1,0x53,0x02, -0xd6,0x2c,0x74,0x90,0x3d,0x42,0xeb,0xb6,0x1e,0x78,0x6f,0xef,0x65,0xa3,0xc9,0x68,0xe9,0x75,0x9b,0x2a, -0xe5,0x13,0xe2,0xdb,0xa3,0xe9,0x6c,0xb3,0x09,0xa2,0xff,0x03,0xad,0x92,0xf2,0xb6,0xca,0xd4,0x4d,0x43, -0x45,0xb3,0xd1,0x7d,0x26,0x1d,0x60,0x2a,0x87,0xe9,0x2f,0x11,0x64,0xfe,0x0f,0x77,0x89,0x58,0x6c,0xf6, -0x76,0x8c,0xc8,0xc9,0x58,0x34,0x52,0x6c,0xa9,0x5f,0xe8,0x54,0x4c,0xab,0xa0,0xa7,0xc5,0x4c,0xb9,0x02, -0xd6,0x3d,0x13,0x29,0x0d,0x98,0xb2,0x16,0x71,0xa6,0x88,0xea,0x9f,0x2b,0x41,0x9d,0x46,0x79,0xc0,0xc2, -0x46,0x74,0x10,0xf7,0xaf,0xdb,0x49,0xdf,0x16,0xfb,0xa1,0x9e,0xb2,0x3e,0xdf,0xaa,0xb8,0x8f,0x58,0x85, -0x4e,0xef,0x3b,0x6a,0xe2,0x54,0x9b,0x64,0xb6,0xb7,0x1a,0x0d,0xad,0x41,0x47,0x50,0xed,0x6c,0xb5,0x25, -0xf3,0xb1,0xf1,0x85,0x50,0x22,0xbd,0x71,0x6e,0x1c,0xac,0xa0,0x10,0xc8,0x1d,0xe2,0xad,0x84,0x38,0x8d, -0x9c,0x5a,0x9b,0x01,0x99,0xe9,0xc2,0x1c,0x7a,0xbb,0x87,0x2c,0xd3,0x82,0xff,0x78,0x2e,0xb9,0x9f,0xbf, -0x34,0xce,0xa0,0xdb,0x0c,0x0f,0xc0,0x2a,0xbc,0x46,0xc3,0x5f,0xe1,0x8f,0x98,0x1f,0x58,0xb4,0xad,0xdd, -0x87,0x6c,0x0c,0xe9,0x92,0xb3,0x2e,0x1d,0x33,0x30,0xa5,0xde,0x51,0x82,0x98,0x0e,0x9f,0x7a,0x83,0x1f, -0x06,0xde,0xa7,0xf7,0x8f,0x0e,0x12,0x13,0xd6,0xc9,0x3c,0xde,0xc7,0x99,0xf7,0xd3,0x9d,0xcb,0x8a,0xd8, -0x80,0xe2,0xea,0x34,0x59,0x52,0x7d,0xd3,0xf8,0xd3,0x4f,0x4d,0x98,0x26,0x7d,0x2a,0xe7,0x67,0x9d,0x08, -0x4d,0x5e,0xd8,0x83,0x78,0xeb,0x4d,0xdd,0xec,0x7e,0xa6,0x6f,0x67,0x86,0xaa,0xef,0xed,0xbd,0x92,0x91, -0xf1,0x70,0x3e,0x9e,0xc5,0xd6,0xd1,0x18,0xc7,0xd4,0x63,0x3e,0x19,0xf5,0xe6,0xaa,0xab,0x32,0xb3,0x70, -0x34,0x74,0x5e,0xd6,0x41,0x7c,0x12,0xf1,0xea,0x58,0xab,0x83,0xc5,0xb6,0xdc,0xb2,0xf9,0xbf,0x63,0xe9, -0x82,0xbe,0xfc,0xe8,0x5d,0xff,0x77,0x91,0x12,0x57,0xf4,0x7c,0xd3,0xbc,0xea,0xfd,0x32,0xf9,0x84,0x8b, -0x1b,0xdc,0xed,0xf9,0x74,0xf8,0xc9,0x70,0x00,0xd6,0x9f,0x77,0x5a,0x77,0x80,0xd3,0xd6,0x88,0x5e,0x94, -0xe9,0x19,0x75,0xe8,0x8e,0xe1,0x45,0x3f,0xd5,0x57,0xee,0x10,0xf7,0xbe,0x97,0xf1,0x3b,0xb0,0x06,0x70, -0xbc,0xc5,0x84,0x41,0x54,0xd8,0xc4,0xa6,0xb6,0xec,0x4f,0x18,0x96,0x32,0xd4,0x48,0x0d,0x68,0xa9,0x83, -0xbd,0x1b,0xb4,0x92,0x23,0xe6,0x09,0x25,0x7f,0xb4,0x6d,0x14,0x38,0x26,0xca,0xbc,0x6f,0x76,0xf0,0x97, -0xea,0xc8,0x67,0x04,0x29,0x94,0xcd,0x3d,0x06,0xe3,0xec,0x19,0x98,0x34,0xe7,0x56,0xf6,0x64,0x65,0x5e, -0x85,0x5e,0xa4,0x3b,0x83,0x72,0xea,0x2c,0x1d,0xd3,0x65,0xbb,0xa3,0xed,0xc5,0x34,0x19,0x7c,0x6c,0x39, -0x7d,0xd9,0xdc,0x0d,0x23,0x40,0xd7,0xe8,0x2f,0xc3,0xe1,0xdd,0xc8,0x63,0x4c,0x09,0xa2,0x01,0x4a,0xa6, -0xae,0xd3,0x1b,0x7a,0xf0,0x22,0x7e,0xa2,0xdf,0xad,0xd7,0x4f,0x86,0x57,0xe9,0xc9,0x6f,0x59,0xfd,0xc2, -0x4d,0x8c,0x17,0x97,0xc5,0x1f,0x3d,0x4f,0x8b,0xbe,0x94,0x55,0xeb,0x61,0xc0,0x58,0xaa,0xf6,0xf4,0x7b, -0x8b,0x5e,0x51,0x11,0xe9,0xd2,0x39,0x27,0x8f,0x5f,0x68,0x3f,0x6b,0x96,0xb3,0x34,0x77,0xd3,0x6a,0x17, -0x4b,0x9d,0x5b,0xf6,0x5a,0xb5,0x6c,0x37,0x86,0xa4,0x0a,0xd3,0xfa,0x55,0xfc,0xca,0xf4,0x98,0x75,0xba, -0x7d,0xa5,0xec,0x92,0xd6,0xe0,0x0a,0x5f,0xc7,0xaf,0xfb,0xd2,0xbc,0xb6,0xd3,0xd4,0xa6,0x43,0x9e,0xb0, -0xc7,0x36,0x9d,0xb1,0x34,0x53,0xff,0xaa,0xa8,0x32,0x54,0x3c,0x08,0x9f,0xc1,0x78,0xce,0x4e,0x27,0x40, -0x7d,0xc1,0xa4,0x67,0xeb,0x89,0xbf,0x72,0x4c,0x5b,0x26,0x69,0x9b,0xbb,0x8f,0x60,0x02,0x53,0xbb,0x26, -0x39,0x63,0x4b,0xbc,0x4a,0x7d,0xb9,0xeb,0xef,0x96,0x5d,0x08,0xc4,0x5d,0x20,0xc9,0xab,0xa2,0x27,0xb9, -0x85,0x74,0x08,0x40,0xab,0x2d,0x75,0xdf,0xdb,0x3b,0xfc,0x72,0x6f,0xeb,0x5b,0x76,0x9a,0x68,0x6f,0xa0, -0xb0,0xab,0x0e,0xb4,0x82,0xdc,0xae,0x23,0x5b,0x5c,0x5b,0x6c,0xc2,0xee,0xa8,0xd1,0xda,0x87,0xdf,0xc7, -0xf5,0xa4,0x93,0x4f,0x6a,0x4b,0x6a,0x21,0x32,0x0e,0x47,0x2a,0x66,0xcd,0xee,0xd6,0x3a,0xed,0x23,0x90, -0x4a,0xff,0xab,0x86,0x99,0xcc,0x23,0x62,0x6a,0xfa,0x0e,0x7c,0x80,0x2c,0xea,0x9a,0x42,0x06,0x93,0xed, -0x5d,0x50,0x07,0xd1,0x61,0x78,0xb8,0x97,0x53,0xff,0xbe,0x65,0x1f,0x9d,0x47,0x29,0xce,0x41,0x00,0x7e, -0xda,0x5a,0x11,0x9f,0x0b,0xca,0x27,0xa9,0x68,0x30,0xd2,0x8e,0x5a,0xe3,0x0e,0xcc,0x19,0xef,0x84,0x69, -0x00,0x03,0x6d,0xa5,0xe7,0xa8,0xb7,0xa5,0xa2,0xea,0x1d,0x46,0x0f,0xa0,0xcc,0x7c,0x40,0x5f,0xec,0xf3, -0x2f,0xd5,0x6a,0x14,0x7d,0xbe,0x97,0xe3,0xfb,0xc3,0xbe,0x21,0xda,0xda,0xb5,0xc6,0xae,0xbb,0x19,0x39, -0x66,0x82,0xac,0xdb,0x2a,0x06,0x8c,0xcd,0x2a,0x9e,0xd6,0x6c,0x4e,0xb0,0x0b,0x14,0x27,0xe3,0x45,0xcb, -0x6d,0x32,0xd5,0xa6,0x9a,0x65,0xb8,0x29,0xfa,0xab,0xc8,0x20,0x15,0xec,0x4c,0xaa,0x95,0xe7,0xe2,0x57, -0xaf,0xac,0xfb,0xd9,0x24,0xcb,0x9e,0x41,0x95,0xe5,0x8b,0xae,0x12,0xd5,0x9d,0x44,0xab,0x76,0xa2,0x31, -0x80,0x63,0xd8,0xb1,0x19,0xe6,0x1a,0x65,0x63,0x7e,0x52,0x4e,0x12,0x9f,0x41,0x65,0xf0,0x26,0x88,0x54, -0xb2,0x3b,0xa8,0xf0,0x4a,0x5f,0x1f,0x46,0xa3,0x4d,0xf8,0x34,0x88,0x9e,0x6e,0xc2,0x5a,0x13,0x3c,0x9b, -0xad,0x6f,0x6c,0xea,0xd9,0x1a,0x01,0xba,0x48,0xf9,0x13,0x58,0x1f,0x18,0xea,0xe9,0x7e,0x08,0xe3,0x8d, -0x9e,0x49,0xa8,0xcd,0x6e,0x01,0x00,0x4a,0x6d,0xd3,0xc7,0x99,0x53,0x22,0x6a,0xf1,0xa7,0x77,0x0e,0xc1, -0xbe,0x84,0x1d,0xc2,0x4c,0x0c,0x1e,0x9b,0x8a,0xe6,0xc6,0x54,0xf4,0x35,0x0d,0xcb,0x6b,0xa1,0x39,0x39, -0xf3,0x6a,0xb6,0xf1,0x28,0xe2,0x1d,0x40,0xe8,0x23,0xd2,0x38,0x43,0x35,0x73,0x51,0x60,0xad,0xd7,0x3d, -0x94,0x16,0x13,0x55,0xd3,0x22,0x65,0x4b,0xdc,0x3c,0x68,0xb0,0x9e,0x0d,0x83,0xdb,0xc4,0x33,0x31,0x1d, -0x94,0x87,0x4f,0xa5,0x77,0x00,0x74,0x64,0x34,0x5b,0xe8,0x28,0x4d,0x8d,0x7a,0xa5,0x6d,0x1f,0xe8,0xa4, -0x67,0xca,0x8d,0xb4,0x66,0x29,0x43,0x2b,0x87,0xdb,0xbf,0x55,0xe4,0xc4,0xb1,0x41,0x6c,0xd9,0x71,0xcf, -0xc4,0xe2,0xf0,0x1b,0xe9,0x22,0x3b,0x65,0xd8,0x4a,0x19,0x4c,0x44,0xc8,0xb9,0xfb,0x52,0x1f,0x2e,0xf4, -0x44,0x6b,0xbc,0xbf,0x26,0x65,0x64,0x0b,0x43,0x68,0x40,0x5e,0x4e,0x5a,0x87,0x6b,0x5a,0x18,0xec,0x66, -0xdf,0x39,0x72,0xd5,0x18,0xc5,0x52,0x20,0x53,0xce,0xb2,0x74,0x3e,0x29,0xe5,0xe8,0xc5,0x98,0xec,0x68, -0x7e,0x5a,0x11,0x93,0xeb,0xda,0x9b,0xeb,0x0e,0x74,0x9c,0x53,0xc4,0x9a,0x97,0xbf,0x80,0xbd,0xbb,0xf3, -0x41,0x27,0x78,0xd9,0x9b,0xf7,0x34,0x32,0xd7,0x3b,0x9c,0x32,0xdc,0x59,0xe5,0x08,0x09,0x7b,0x9e,0x67, -0x7f,0xa4,0xf3,0x9d,0xf4,0x7a,0x09,0x0c,0x13,0x38,0x8c,0xed,0x78,0x03,0xc9,0xb1,0x51,0x4a,0xf6,0x09, -0xbf,0x70,0xb0,0x10,0x02,0xc3,0x6b,0x9f,0x08,0x0f,0x4d,0xb4,0xb4,0xa6,0x49,0xf6,0x68,0x05,0xbb,0x0a, -0x62,0xfa,0xaa,0xf0,0x41,0xac,0x48,0xe9,0x1b,0x86,0x54,0x67,0x6b,0x4e,0x91,0xad,0x82,0x7d,0xc1,0x0b, -0xff,0xfb,0x20,0xfc,0xdd,0x98,0x70,0xa5,0xea,0xd0,0xc5,0x9b,0x0b,0x23,0x0b,0xf8,0x30,0x32,0xe5,0x2d, -0x3f,0x53,0x50,0x76,0x62,0x6b,0xaa,0xdd,0x26,0x7d,0xd8,0x99,0x86,0x87,0x46,0x69,0xfa,0x40,0x4c,0x14, -0xd2,0x4d,0xf8,0x58,0xce,0x7b,0x88,0x67,0xd0,0x5b,0x7f,0xcf,0x33,0x04,0xd2,0xc4,0xa2,0x62,0xa4,0x9d, -0x1b,0x65,0x06,0x46,0xc4,0xf0,0x2b,0xf9,0x39,0xe4,0x5b,0x05,0x78,0xd7,0x76,0xdc,0xb1,0x31,0x91,0x1b, -0x1c,0x6c,0xeb,0x21,0xd7,0x1a,0x46,0x01,0x0d,0x42,0xf5,0x38,0x1d,0xe3,0x81,0x65,0xa3,0x1a,0xe4,0x83, -0xf8,0x31,0xce,0x6d,0xda,0xea,0xfb,0x33,0x29,0xfa,0x73,0xdb,0x00,0x5e,0x6a,0xca,0xb8,0xc1,0x8e,0xf5, -0x5a,0xaa,0x4e,0xf8,0x9c,0x47,0x03,0x04,0x9b,0xd3,0x81,0x94,0xa5,0x98,0x42,0x57,0xaa,0xf8,0xc6,0x32, -0x61,0x8e,0xbe,0x18,0x29,0x00,0xa4,0x57,0x55,0xba,0x9a,0x17,0x51,0x19,0x32,0x1d,0x8a,0x68,0x5b,0x68, -0x16,0x06,0xfc,0x20,0x71,0xa4,0xc5,0xaf,0x36,0xb9,0x88,0x6e,0xbc,0xfb,0x5e,0xd4,0x95,0x44,0x8b,0x23, -0x2f,0xdc,0xd8,0x20,0x08,0xef,0xbc,0xa7,0xc7,0x03,0xf3,0xb8,0x4c,0xdf,0x65,0xc5,0xaa,0x52,0x8d,0x77, -0xbe,0xfd,0xf7,0xb6,0x44,0x9b,0x4d,0x48,0x8f,0x04,0xdc,0x20,0xba,0x61,0x25,0x56,0x9f,0x7c,0x0b,0xf6, -0x72,0xf8,0xd3,0x12,0x1e,0x85,0xe9,0xf4,0xb3,0x19,0x71,0x0a,0x8c,0x80,0x9b,0x4e,0x3f,0xe7,0xbf,0x5f, -0xcc,0x18,0x30,0xbb,0x9d,0x14,0xc7,0x34,0x9e,0x81,0xf7,0x24,0x5c,0x0c,0x7d,0x08,0xa3,0x77,0x5c,0xb0, -0x31,0x78,0xd8,0xa8,0x08,0x3e,0xa7,0xa5,0x22,0xda,0xb1,0x5b,0xeb,0xe2,0x46,0x02,0xf1,0x72,0xc1,0xcc, -0xe5,0x57,0x3a,0xa7,0xcf,0x82,0x89,0xaa,0x9d,0x5a,0xcc,0x7e,0xca,0x98,0x6a,0xa8,0x6b,0x3c,0xf0,0xf1, -0x33,0x41,0x8d,0x71,0xf9,0x25,0xa5,0x3a,0x0c,0xa2,0x7b,0x77,0x7d,0x0f,0xfa,0x2a,0xc9,0x8b,0xa1,0x7d, -0x8b,0xf9,0x5c,0xdf,0x21,0x26,0x02,0xa5,0xe7,0x6f,0xff,0x3a,0xa3,0xda,0xff,0xad,0x93,0x20,0xc2,0x0f, -0xd8,0x1b,0xa7,0xc0,0x8d,0xd6,0x04,0xf6,0x2d,0x9b,0x5d,0x94,0x0e,0xa0,0x85,0x7b,0xc6,0xb8,0x7d,0x9e, -0x0e,0xb9,0x0b,0x94,0xe9,0x3f,0x32,0x91,0x40,0x5e,0xdc,0x9e,0x49,0xca,0xd6,0x89,0x4e,0x8f,0x47,0x44, -0x86,0xcf,0x52,0xbd,0x7f,0x31,0x74,0xc5,0x1b,0xda,0x52,0x76,0x47,0x81,0xdc,0xe4,0x1a,0xda,0xc0,0xa7, -0x83,0xb6,0x31,0xc4,0xdd,0xaf,0x83,0x7d,0x7d,0x1d,0xf0,0xc0,0x8c,0x66,0x02,0xd7,0xac,0xfb,0xb0,0x46, -0x93,0xa9,0xb4,0xdc,0x7a,0x62,0x8f,0xd6,0x67,0xb0,0x03,0x0b,0xcf,0xd4,0x14,0x82,0x9e,0xf4,0xc3,0x52, -0xc7,0x7e,0x53,0x6f,0x91,0x16,0x75,0x63,0x72,0xed,0x3a,0x62,0xa8,0xff,0x38,0x26,0x21,0x44,0x8e,0xac, -0xde,0xed,0xd6,0xeb,0x0f,0xe5,0x3b,0xe2,0x02,0x46,0xdb,0xfa,0x3c,0xff,0xe7,0x46,0x5b,0x4d,0x7f,0x95, -0x12,0x0f,0x0a,0x48,0x74,0xeb,0x1f,0xfd,0x31,0xfd,0x14,0xd2,0x52,0x0f,0x5d,0x3b,0x6d,0x24,0x4e,0xd6, -0x0d,0x0d,0xdf,0x07,0x85,0xad,0xb7,0xa2,0x44,0xc1,0x88,0x2e,0x6c,0xad,0xde,0xd0,0xf6,0xbb,0x30,0x8f, -0x35,0x18,0x75,0x2c,0xec,0x80,0x9f,0x59,0x70,0x08,0x62,0xad,0x54,0x4c,0x70,0x10,0x04,0x07,0x1e,0xed, -0x02,0x81,0xb8,0x18,0x80,0xac,0x7b,0xf2,0x68,0x02,0xe0,0x63,0xa2,0x23,0xbb,0xfa,0x76,0x97,0x6f,0x7f, -0x56,0xb7,0xc4,0x67,0x71,0xe4,0x20,0x33,0xd5,0xe8,0xf4,0xe4,0xdd,0x6d,0x5e,0xda,0x2f,0xee,0x13,0x1f, -0xe9,0xdd,0xb1,0xdf,0xc9,0x8c,0xda,0x2f,0xf5,0x74,0x94,0xa2,0xfe,0xad,0x92,0xf8,0x0c,0x96,0x62,0x26, -0x52,0x92,0x82,0x24,0xb2,0x82,0x30,0x68,0xe7,0xba,0x8e,0x35,0xea,0x75,0x21,0x47,0xbe,0xc2,0xcc,0x56, -0x9d,0xf9,0xe0,0x90,0xb3,0x1f,0x78,0xfb,0x1e,0xcf,0xdf,0x36,0xbd,0x69,0x61,0x77,0xc7,0x4c,0x5e,0x98, -0xa7,0x6b,0xe6,0x3d,0x40,0xa6,0xa1,0xbe,0xb6,0x9f,0xef,0x7f,0x0e,0x6b,0x2b,0x4f,0xa9,0xe8,0xd9,0x0f, -0xdb,0x8e,0xda,0xa2,0x3a,0x28,0x9b,0x74,0x67,0xcd,0xee,0xae,0x7d,0xaa,0xb8,0xd5,0x52,0x3b,0x9c,0x87, -0xb0,0x66,0x2d,0x18,0xf9,0xdd,0xb3,0x76,0x3c,0xaf,0x67,0x1b,0x78,0xe7,0x1e,0x4f,0xde,0xc3,0x23,0x74, -0x9b,0xfd,0x34,0xec,0x5f,0x57,0xc4,0x28,0x57,0xe1,0x35,0x7b,0x06,0x9f,0xf9,0xef,0x6c,0x9b,0xd3,0xf1, -0xf9,0x58,0x2e,0x96,0xd4,0xaa,0x65,0xbc,0x9c,0x9e,0x8b,0x08,0xbc,0x9a,0x2c,0xb7,0xaf,0xbf,0xf7,0x11, -0x1a,0xbe,0x6c,0xb3,0xc0,0x94,0xfd,0x45,0x7c,0x4e,0x3d,0x85,0xf8,0xb9,0x31,0x07,0x2d,0xdc,0xbd,0x00, -0xf0,0xaa,0xd5,0x9a,0x8d,0x59,0xff,0x54,0xc8,0x45,0x3c,0x4d,0x26,0xef,0xac,0x0d,0x3f,0x7a,0xd7,0xc4, -0x6b,0x62,0xe4,0xcb,0x4b,0x5d,0xb9,0x77,0xe1,0x19,0x55,0x8e,0xad,0xcb,0x97,0xb6,0x75,0xf9,0xb2,0x65, -0x5d,0xbe,0x6c,0x59,0x97,0xc3,0x54,0x3c,0x15,0xa0,0xad,0x79,0xec,0x9a,0x8b,0x53,0x87,0xcc,0x71,0x75, -0x6f,0x16,0x2e,0x71,0xf5,0xce,0xd2,0xef,0x4e,0xe7,0x33,0xea,0x8d,0xc1,0x80,0x1e,0x2f,0xe9,0x3f,0xea, -0x15,0xca,0x9d,0xd2,0xc7,0x23,0x5a,0x9c,0x17,0xb0,0xd3,0x22,0x1a,0xa7,0x0d,0xe1,0x97,0x96,0xdc,0x7b, -0x30,0xb8,0xa6,0xf4,0x7c,0xd6,0xbc,0x41,0xc9,0xb0,0xc0,0x9f,0x87,0xd7,0x33,0x65,0x85,0x67,0xf8,0x96, -0x4b,0x9a,0xc9,0xf0,0x60,0xfb,0x1f,0x69,0x15,0x2c,0x9b,0xd9,0xad,0x5b,0x42,0x8a,0x7e,0xa8,0x21,0xd8, -0x24,0x6e,0x19,0xf0,0x5d,0x1e,0xf0,0x5d,0x67,0xc0,0x89,0x8d,0xa7,0x96,0x52,0x56,0x68,0xc7,0x9f,0x6b, -0x83,0xee,0x9d,0x6b,0xda,0x4b,0xa1,0x99,0x45,0x6c,0x44,0x43,0xb7,0xae,0xf7,0xe3,0x8c,0x1b,0x41,0x2b, -0xfd,0xfa,0x2f,0x25,0x5d,0x8c,0xf6,0xf6,0xae,0x0f,0xca,0xfb,0xf1,0x68,0xb3,0xe9,0xd9,0x78,0x2d,0x47, -0x67,0x3a,0xdb,0x2c,0x99,0x55,0xab,0xb8,0x8b,0x1e,0x42,0x24,0xfa,0x44,0x61,0x2a,0xb6,0x5a,0x66,0x31, -0x11,0x44,0xad,0x95,0xe6,0x9c,0xd8,0x7c,0xf9,0x5e,0x58,0xfc,0x06,0xbf,0xed,0x87,0x19,0x4c,0x9e,0x83, -0xa8,0x30,0x36,0x89,0xc0,0xce,0x98,0xa6,0x21,0x3c,0xdf,0xc3,0x7c,0x16,0xda,0x45,0xb5,0x4c,0xfc,0xfc, -0xb6,0x57,0xc3,0xc4,0x32,0x76,0x77,0x34,0xfe,0x30,0x8f,0x2e,0xb8,0x41,0x36,0x5e,0x38,0x7b,0xd3,0xd0, -0x19,0x09,0x60,0x5c,0xd9,0x34,0x61,0x7e,0xa7,0x84,0xdd,0xb6,0xe0,0xb8,0xe2,0xc9,0x26,0xe8,0xdb,0x51, -0x91,0xd5,0x88,0xa3,0xc4,0x44,0x05,0x38,0x43,0xe9,0x99,0xe8,0x26,0x2f,0xea,0xa8,0xf4,0xbb,0xdb,0x27, -0x1c,0x7a,0x44,0x15,0xf4,0x6d,0x8f,0x5f,0x60,0xe3,0x6b,0x8e,0xde,0x70,0x9b,0xe0,0x3a,0x30,0xc0,0xed, -0x20,0xd3,0xf2,0x81,0x92,0x0d,0xf1,0xab,0xc6,0x3e,0xb1,0x62,0xdb,0x74,0xc4,0x24,0x13,0x8f,0x83,0x94, -0xc1,0xf1,0x7c,0x04,0xe8,0x42,0x14,0x0c,0xa7,0x29,0xf4,0x75,0xd1,0x6c,0xc3,0xcc,0xcb,0x84,0x19,0x28, -0x28,0x72,0x2e,0xd0,0x4f,0xfc,0x90,0x6f,0x77,0x73,0x99,0xd1,0x50,0xc2,0xd1,0x00,0xb4,0x5a,0xd8,0xde, -0x38,0x5b,0x92,0x0c,0xeb,0x7c,0x8e,0xe9,0xa9,0xce,0xe7,0xfd,0x79,0xa4,0x1d,0xfe,0xc7,0x42,0x02,0x32, -0x87,0xd0,0xda,0x3e,0xdf,0xb0,0x0b,0x17,0x74,0x09,0x38,0x6a,0xad,0xd7,0x38,0x81,0x34,0xbb,0x9c,0x98, -0xa4,0x63,0x65,0x27,0xf9,0x79,0x7f,0x91,0x4b,0xed,0x33,0xca,0xdc,0xc1,0x96,0x99,0xcb,0x9f,0xf3,0xbc, -0x0d,0xbb,0x55,0x6c,0x6d,0x0c,0x1d,0xcf,0x3a,0x04,0x1c,0x65,0xed,0xe7,0xcb,0x49,0x3d,0xe4,0x9c,0xda, -0x7e,0xb2,0xd7,0x97,0x8b,0x08,0x2f,0xa4,0x7c,0xf7,0x9d,0x3c,0x37,0x66,0xa6,0x71,0xde,0x09,0x10,0xcb, -0x7e,0x6c,0x1c,0x6c,0xb6,0x69,0x37,0xef,0xd6,0x2a,0x8a,0xa9,0xef,0xca,0x4f,0x83,0xb6,0x97,0x63,0xe3, -0xf4,0x34,0xfe,0x5f,0xe8,0xab,0x3a,0x29,0x1d,0xf8,0x29,0x23,0x51,0xa6,0x79,0x56,0x9c,0x26,0x22,0xce, -0x6d,0xae,0xb1,0x24,0x2f,0x1c,0x15,0xb6,0x46,0x81,0xe4,0x52,0xb2,0x39,0x9d,0xdd,0x8a,0xa2,0x17,0xce, -0x0a,0x32,0xbe,0x27,0xc4,0x11,0xc3,0x20,0x76,0xdb,0xfb,0xa7,0x6e,0xa8,0x3b,0x88,0x9f,0x9e,0xa2,0xc8, -0x27,0x6c,0x45,0xbb,0x6e,0xae,0x99,0xe0,0xee,0xee,0xaa,0x18,0x58,0x10,0x32,0x41,0xa9,0xb4,0x5e,0xff, -0x9b,0x1e,0x24,0x27,0xec,0xb2,0xc9,0x40,0x4a,0xac,0xc0,0x88,0x16,0x3e,0xd1,0xf1,0x50,0xeb,0x33,0x70, -0x0b,0xa7,0x05,0x15,0x2a,0xab,0x8f,0x2d,0xff,0x48,0xdf,0xcb,0x1a,0x75,0x30,0x41,0xb7,0x70,0xe2,0x59, -0x2a,0x3c,0x02,0xfd,0x4a,0x2b,0xfc,0x36,0xa1,0xbe,0xea,0x67,0xd9,0x6d,0x9f,0x48,0xfb,0xce,0x64,0xc0, -0x4d,0x0a,0x9b,0x7b,0xb6,0xdf,0xa2,0x16,0x02,0x01,0xc6,0xc9,0xf2,0xa3,0x24,0x00,0x8c,0x03,0xa8,0xa7, -0xc4,0xd1,0x97,0x7d,0xf8,0x30,0x52,0x87,0x9e,0xda,0xee,0x9a,0xbd,0x41,0x02,0x00,0xb0,0x06,0xf8,0x82, -0x61,0x1c,0xb7,0xe0,0x83,0xa9,0x68,0x65,0xba,0x53,0x81,0xfb,0x80,0x1e,0xec,0x4b,0x7d,0xd1,0x97,0x5a, -0xcc,0x15,0xff,0x9b,0x03,0x65,0x39,0xb1,0xea,0x49,0x63,0x3d,0xaa,0x61,0xc8,0x7d,0xdd,0x87,0xa2,0xd3, -0xce,0x6a,0x5b,0x99,0x2a,0xcc,0x5a,0x93,0x3f,0x8c,0xa4,0xf8,0xe4,0xc0,0x60,0x89,0xbd,0xa1,0xf7,0x10, -0xfb,0x40,0x7d,0xd3,0x96,0x0a,0x6a,0xb0,0xb2,0x53,0xbf,0x73,0xee,0x83,0xd7,0x5b,0x20,0x38,0x65,0xa7, -0xad,0x0d,0x50,0x25,0xa8,0xf7,0x0f,0x91,0x24,0xfd,0xbd,0x95,0xa0,0x91,0x3b,0x4f,0xf3,0xa3,0xd1,0x24, -0x1f,0xd4,0x51,0xce,0x09,0xe9,0x60,0xdf,0xc9,0xcb,0x32,0x8b,0x1f,0xe7,0x47,0xf5,0x38,0x47,0xac,0x9d, -0xb4,0x6d,0x92,0x00,0x20,0x0e,0x3a,0xe7,0xdf,0xf2,0xf5,0xe1,0x07,0xbe,0x5e,0xb4,0x9b,0xe1,0x40,0xbb, -0xc4,0xa6,0xa2,0xe3,0xfd,0x7d,0xb0,0x2e,0x63,0x9d,0x4b,0xe9,0xe4,0x72,0xfe,0xb1,0xb9,0x0c,0x06,0x25, -0x55,0xa7,0x37,0x13,0x36,0xc2,0xd1,0x73,0x9b,0x0e,0x36,0xb1,0x35,0xd3,0x7f,0x67,0xd1,0xda,0xd5,0x4e, -0x96,0xdf,0x94,0xc9,0x3c,0x2b,0x00,0x99,0xc5,0xeb,0xfe,0xa4,0xb8,0xc6,0x35,0x1d,0xf4,0x53,0xfc,0x2e, -0xe9,0xf0,0x79,0x55,0x94,0x73,0x5c,0x67,0x97,0xc9,0x39,0x1e,0x6e,0x82,0x86,0x9d,0xba,0x9a,0xc5,0x95, -0x7f,0x15,0x34,0xb9,0x55,0xab,0x93,0xcb,0x0c,0xf2,0xa8,0xb0,0x4c,0x89,0xf5,0xe9,0x26,0x5f,0x21,0xb9, -0xde,0xbf,0x2c,0x04,0x42,0x6d,0xd0,0x54,0x35,0xd5,0x74,0xb8,0x27,0x3e,0xaf,0x2f,0xc3,0x37,0x3c,0xb5, -0x7e,0x4b,0x21,0x7c,0x8d,0xbb,0xcc,0x5e,0x2b,0x0e,0x4a,0xfc,0xa3,0x3e,0xfa,0x33,0x7e,0x82,0xd1,0x7d, -0x8d,0xa2,0x53,0x23,0x4e,0x95,0xc0,0xa0,0xc4,0x41,0xac,0xd8,0x6d,0x0e,0xc5,0x6b,0x59,0xd9,0xb8,0xa2, -0x93,0x10,0x1d,0xe6,0x76,0x81,0x7a,0xa1,0x30,0x3e,0xaa,0x80,0x91,0xd3,0x38,0x46,0xa2,0x46,0x37,0xcd, -0x20,0x49,0x51,0xc7,0xd9,0xf5,0xba,0x0a,0x42,0xe5,0x69,0x53,0x50,0x8e,0x70,0x64,0x02,0x9a,0x1a,0x65, -0xb1,0x68,0xb2,0x60,0xf1,0x6c,0x66,0xe0,0x65,0x0b,0x49,0xaf,0x3c,0xaa,0x4a,0x41,0xb3,0xe2,0x5c,0x6d, -0x76,0x6b,0x87,0x8d,0x11,0x9a,0x62,0xcd,0x11,0x5a,0xda,0xc0,0xd8,0x3b,0xba,0x1b,0x03,0xd4,0x79,0x0e, -0x0c,0x1e,0xab,0xda,0x0b,0xba,0x95,0xd6,0xe0,0x0a,0x72,0x61,0xc6,0xd6,0xfd,0x40,0x3d,0x92,0x50,0xa9, -0x59,0xa2,0x6c,0x5b,0xf1,0x0c,0xa2,0x22,0x88,0x51,0x26,0xba,0xf8,0xc4,0xe0,0xb0,0x57,0x13,0x23,0x26, -0x0b,0x22,0x84,0x54,0x58,0x05,0xa6,0xf7,0x37,0xe1,0xb7,0xb1,0xe8,0x08,0x69,0xc6,0xb5,0xd4,0x16,0x8e, -0x19,0x12,0x23,0x22,0x7d,0x67,0x0d,0xe7,0xae,0x3a,0xae,0x8a,0x34,0xe7,0x8d,0x40,0x94,0xc4,0x6e,0x88, -0xb1,0x22,0xbe,0xe6,0x40,0xcb,0xd4,0x32,0xe6,0x4e,0xb5,0xdb,0x6a,0xd4,0xc4,0xd7,0xa5,0x4c,0xa9,0xb4, -0x13,0x3f,0x63,0x47,0xb4,0xc2,0xc8,0x7c,0xe3,0xd4,0xb2,0x4e,0x7a,0x64,0x84,0xc1,0x71,0x97,0xbf,0x6d, -0x43,0xe0,0xf6,0x21,0x8a,0x01,0xb4,0xe1,0x34,0x86,0x33,0x13,0x55,0x34,0x5e,0x98,0x52,0xa0,0x89,0xb1, -0x31,0x6c,0xc0,0xdd,0x9c,0xea,0x7e,0xe5,0x33,0x39,0x1d,0xeb,0x88,0x95,0x3d,0xb5,0x64,0x75,0xa8,0xa5, -0x62,0x4b,0xef,0x11,0x99,0x7e,0xf6,0x08,0x04,0xd7,0x4f,0x24,0x90,0x84,0xa2,0xd5,0x5f,0xb5,0xb0,0x20, -0x5e,0xc2,0x79,0xcd,0x78,0xfe,0x15,0x2c,0x58,0x65,0x57,0x43,0x56,0x55,0xc7,0xbe,0xb1,0xd6,0xf3,0x13, -0xad,0x54,0xb3,0x67,0x9f,0xe2,0x67,0x6b,0x06,0xd7,0x46,0x98,0xd6,0x70,0xd7,0xf2,0x1e,0x5a,0xb0,0xe4, -0xd1,0xe1,0xd3,0xc2,0xc6,0x95,0xaf,0xd0,0xb3,0x4b,0x14,0x35,0xba,0x71,0x1b,0xb1,0xbf,0x9b,0x63,0x27, -0x6f,0x1c,0x0c,0x0c,0x78,0xf9,0xc8,0x9c,0xa9,0xe0,0x3f,0xcd,0x90,0x37,0x05,0xbc,0x9c,0x6d,0x07,0x46, -0x84,0x11,0x92,0x56,0x88,0xf3,0xfa,0x2a,0x96,0x66,0xa8,0x13,0x44,0x49,0xb4,0xe6,0xb6,0xd6,0x68,0xc4, -0x95,0x42,0xfb,0x98,0xf6,0x22,0xaf,0x28,0x80,0x99,0x42,0x6b,0x4d,0xb2,0xf0,0x10,0xad,0x2b,0x8d,0x55, -0x04,0x87,0xdc,0xd8,0xed,0x01,0xb7,0x29,0x01,0x99,0xa3,0xce,0xf8,0x8a,0xfb,0x5f,0xac,0xd7,0x74,0x86, -0x42,0xc0,0x47,0xbf,0x64,0x25,0x19,0xcd,0x20,0xc4,0x04,0xbf,0x1d,0xfc,0x85,0xc1,0xcc,0x6c,0x6d,0x50, -0xfc,0x83,0x06,0x13,0xf1,0x02,0xad,0x0b,0x52,0x06,0x19,0x6c,0x92,0xfa,0x43,0xd8,0xd5,0x28,0xc5,0xbb, -0xbb,0xbf,0x87,0xcf,0xfd,0x20,0x74,0x35,0xf4,0xfd,0xb6,0xb8,0x87,0xb7,0xd8,0x3b,0xdc,0x82,0xad,0xd2, -0xb5,0x95,0x32,0x1c,0x61,0x9f,0xc9,0xd4,0x27,0x62,0x1f,0xe5,0x85,0xde,0x27,0xc2,0x67,0x34,0x4c,0x5e, -0x8b,0xc1,0x40,0x7a,0x10,0xbf,0xf5,0xba,0x10,0x6e,0x63,0xcd,0xfc,0xb1,0x44,0xb5,0x5a,0x4b,0xa4,0xab, -0xb0,0xbd,0x5d,0x82,0x46,0xe4,0x8d,0x02,0xc8,0xd5,0x2f,0x86,0x9e,0x91,0xdc,0xb9,0xac,0xca,0xe4,0x30, -0xba,0x27,0xd6,0xd5,0x8d,0x86,0xb2,0x6d,0x82,0xd3,0xdb,0x2a,0x66,0xa9,0x0e,0xd8,0x00,0xcf,0x6a,0x87, -0x6b,0x7c,0xc5,0x2b,0xc0,0x63,0xac,0x4a,0xef,0x03,0x4d,0x96,0xa4,0xba,0xcd,0xea,0xc3,0xde,0x26,0x12, -0x0d,0xf8,0x20,0x3b,0xd7,0x74,0x83,0x1d,0x1b,0x77,0xdb,0x70,0x29,0x48,0xbf,0x56,0x8d,0x1a,0x03,0x2a, -0xa9,0x54,0x9d,0x76,0xea,0xc3,0x5b,0xf0,0xd8,0xed,0x78,0xe0,0x7c,0x32,0x44,0x75,0xab,0xa3,0xff,0x94, -0x82,0x17,0xf1,0x1c,0xa1,0xb2,0xe6,0x28,0xa8,0xf9,0x3c,0x3e,0x49,0x05,0x35,0x74,0x59,0xd2,0x65,0xa3, -0xaf,0xd3,0x0f,0xa7,0x5e,0xe4,0x29,0x24,0xd2,0x65,0x69,0xd8,0x0a,0xba,0xb7,0x34,0xb4,0xe6,0x0e,0x39, -0x34,0xcf,0xc3,0x73,0x51,0x45,0xe2,0xa9,0x52,0x86,0x0a,0xa2,0xdc,0x8f,0x2f,0x9e,0xd3,0x9a,0xc0,0x63, -0xbe,0x0e,0xad,0xa8,0xa3,0x78,0xa8,0xaf,0xb9,0x0a,0xac,0x8b,0x36,0x86,0x0f,0x27,0xfa,0x09,0x6b,0xdc, -0xaf,0xba,0x6e,0x41,0x0d,0x83,0xc7,0x5b,0x9e,0xd1,0x98,0xe7,0x63,0x9c,0x81,0x10,0x82,0x50,0x60,0xcc, -0x2c,0xbd,0xab,0x16,0x38,0x36,0x8f,0x24,0x9c,0x0e,0xd0,0x59,0xd9,0xf8,0xb4,0x82,0x99,0x83,0xc2,0x72, -0x54,0x08,0x81,0x46,0xe5,0x5b,0x6e,0xba,0xbe,0x3d,0x0d,0xa7,0x3b,0x9d,0xf5,0x1c,0xb5,0xda,0xa0,0x43, -0xe9,0x2e,0x1f,0x47,0x72,0x9d,0xb5,0xad,0x41,0x4d,0x4d,0xcf,0x33,0x11,0x76,0x08,0x3d,0x7c,0x7a,0x0e, -0x7e,0x3e,0x12,0xf4,0xea,0xe9,0xcf,0xc7,0x07,0xc7,0xa3,0xfb,0x11,0xbb,0x7d,0xd6,0xc7,0xe5,0x71,0x7e, -0x7c,0x36,0xbb,0x1b,0x4c,0xdd,0xfb,0xe3,0x83,0xc9,0x7d,0x7f,0x12,0x1d,0x51,0xda,0xc3,0xfb,0x6b,0x76, -0xf7,0xfa,0x0d,0x99,0x0c,0xa7,0x3f,0x47,0x9f,0x1c,0x4f,0x8f,0x87,0xe1,0xec,0xee,0x9d,0x83,0xb1,0x09, -0x90,0xbb,0xc5,0xeb,0x0a,0xa2,0x21,0xeb,0xc8,0xef,0xc3,0x69,0x33,0x2f,0x88,0x8e,0x0d,0x94,0x71,0xaa, -0x48,0x18,0x34,0x79,0x3f,0x74,0x5c,0x50,0x26,0x6a,0xe2,0xb5,0x2d,0x4f,0x88,0x9c,0xd3,0xa6,0x85,0xb8, -0x53,0xd3,0x59,0xd4,0x4a,0xe3,0xf3,0x1c,0x05,0xe4,0xa3,0x1d,0xb0,0xc3,0x22,0xb6,0x4e,0x97,0x32,0x36, -0xb4,0x0d,0x63,0xec,0xdf,0xb0,0x1a,0xb9,0xdf,0x8b,0xc6,0x46,0x69,0xce,0xf8,0xce,0x86,0x47,0x6c,0x94, -0x4c,0x76,0x10,0x1c,0x07,0xb6,0x1a,0x73,0x44,0xc5,0x13,0xb6,0x4e,0x66,0x12,0x44,0x71,0x34,0xae,0x8f, -0x4a,0xc6,0xc2,0x91,0x70,0x1a,0xc6,0x5a,0x2e,0x63,0x9c,0x45,0xe0,0x77,0x37,0x90,0x29,0x81,0x31,0x46, -0x72,0x8b,0x80,0x98,0xcf,0xce,0x4a,0x75,0x0e,0x0b,0x2d,0x29,0x17,0xcb,0x1a,0xfc,0xfe,0xe1,0xc4,0x59, -0x99,0x10,0xac,0xe6,0x46,0xe7,0xd8,0xa7,0x80,0x73,0x4b,0x2a,0x14,0x68,0x37,0x33,0x52,0xbb,0x87,0x01, -0xe3,0xfb,0xf6,0x1e,0xcb,0x6f,0xfd,0x70,0x24,0x60,0xb4,0x7d,0xa2,0x82,0x5d,0x95,0xb2,0xab,0xf2,0x23, -0xf6,0xca,0x6c,0xe1,0x13,0xee,0xd5,0xc8,0xd4,0x43,0x7b,0xa5,0x28,0x30,0xc4,0x37,0x69,0xf8,0xad,0xf2, -0x3e,0x3c,0xae,0xee,0xfa,0x47,0xd3,0xe3,0xab,0xe3,0x1f,0x66,0x83,0xfb,0xc1,0xf4,0xe7,0xfb,0xb3,0xbb, -0xeb,0x4f,0x6c,0x07,0xc4,0x47,0x69,0xdc,0x00,0xc5,0xf7,0xcf,0x67,0x01,0xc4,0xdc,0x75,0x46,0xd8,0x70, -0x94,0x54,0x56,0xb7,0xae,0x4c,0x20,0x4a,0xda,0xb1,0x44,0x9b,0x8d,0x60,0x0f,0xde,0x7d,0xb9,0x6e,0x1c, -0xf4,0x66,0x2c,0x26,0x13,0x2e,0x33,0xfe,0x6c,0x32,0x15,0xdb,0x10,0x96,0xb0,0xce,0xa2,0x6f,0x0d,0xde, -0x61,0x08,0x23,0xcb,0xdd,0x72,0x8a,0xf4,0x9a,0x23,0xdc,0x65,0xb9,0xa6,0x00,0xca,0x4f,0xc0,0x9e,0xe7, -0x81,0x1a,0xf2,0x20,0xea,0x80,0x7c,0xd7,0xe6,0x1d,0x1b,0x5d,0x69,0xdc,0x44,0x62,0x27,0xe9,0x34,0x53, -0xd5,0x49,0x7e,0x8a,0x3a,0x9f,0xa7,0x13,0x2c,0xdb,0x48,0x62,0x7a,0x1b,0xc8,0x77,0xdc,0x31,0xe6,0x31, -0xb6,0x60,0xfe,0x38,0xac,0xb5,0xda,0x8b,0x57,0x6b,0x0f,0xa2,0x63,0x9e,0xf2,0x10,0x13,0xfd,0x51,0x61, -0x37,0x50,0x64,0x0f,0x96,0x75,0x2d,0x68,0xa8,0x2a,0xfc,0xa3,0x8b,0x25,0xca,0xf8,0xe6,0xe5,0x2c,0x98, -0xa8,0x0b,0x16,0xb9,0xab,0xc6,0xb1,0xbe,0x95,0x98,0x3b,0x3c,0xb1,0x91,0xd2,0x35,0xcd,0xcd,0xe8,0x20, -0xdb,0x76,0x65,0x41,0xa8,0x61,0x46,0x3d,0x92,0x9c,0x89,0xdf,0xcf,0x42,0x6b,0x65,0xc7,0x87,0x2a,0x88, -0x94,0xa3,0x12,0xe7,0x06,0x9a,0x0f,0x52,0xf7,0x03,0x59,0x9d,0x51,0x1b,0x02,0x75,0xd2,0x6c,0x29,0x43, -0xf8,0xe0,0xbf,0x9f,0xa8,0x5f,0x9e,0xb0,0xb4,0xc6,0xf9,0x13,0x83,0xd7,0xeb,0x4b,0xae,0xc1,0x66,0xfc, -0xc8,0x0e,0x16,0xc0,0x53,0x32,0x7c,0x83,0x0b,0x3f,0x57,0xf6,0x63,0xbf,0xaa,0x29,0x2d,0x9c,0x6b,0xb5, -0x86,0x82,0x92,0x6e,0xbf,0xcb,0xeb,0x6c,0xb1,0x66,0x47,0x89,0x83,0xf0,0x41,0x1a,0xdf,0xb0,0x3e,0x8d, -0x92,0xb0,0xc0,0x41,0x45,0x60,0xc1,0x35,0x3b,0x63,0x42,0xe0,0x40,0xdf,0x41,0x68,0x30,0x76,0x49,0x20, -0x24,0xf7,0x5d,0x81,0xd9,0x79,0xaa,0x6b,0x68,0x9f,0xfc,0xec,0x45,0xde,0x4f,0xda,0x18,0x0d,0x1e,0xbe, -0x93,0x47,0xf9,0x38,0xed,0x92,0x37,0x89,0x11,0xc0,0x01,0x25,0x1b,0xf2,0xb6,0x09,0x4f,0x17,0x45,0x95, -0xda,0x68,0xfa,0x9d,0x30,0xb4,0x36,0x35,0xc6,0xd9,0x1f,0xaa,0xe3,0x0e,0x29,0x56,0x3b,0x33,0xaf,0xda, -0x86,0x68,0xa8,0xe8,0x44,0x47,0x19,0x63,0xb1,0x34,0x94,0x14,0xe6,0x9a,0x10,0x4c,0x63,0x9b,0x6d,0x59, -0x79,0xb2,0x5b,0x52,0x23,0xf6,0x3c,0x04,0x74,0x4f,0x32,0x49,0x44,0x90,0x4e,0xc4,0x13,0x4a,0xf2,0xb6, -0x0f,0xce,0xb6,0xed,0x8b,0x31,0x93,0x83,0x9b,0xc2,0x48,0xb4,0x9c,0xb3,0x7c,0x9b,0x5e,0x36,0xda,0x2e, -0x97,0x60,0xd3,0xc1,0xba,0x60,0x71,0x28,0x55,0xa0,0x57,0x30,0x3c,0xe9,0x41,0x6f,0xd6,0xd8,0xcb,0xdc, -0x2b,0xa1,0x9a,0xcf,0x41,0x03,0xc9,0xcc,0xa4,0x59,0x93,0x13,0x90,0xab,0x48,0xd1,0x11,0xa6,0x5c,0xea, -0xc2,0x41,0xd4,0x93,0x81,0x27,0xbe,0x9a,0xce,0x9c,0x98,0x4f,0xb0,0xef,0xd7,0x54,0x38,0x62,0x98,0x9f, -0xf9,0xbc,0x35,0x8a,0xdb,0xb6,0x47,0xbb,0x75,0x6e,0xb4,0x09,0x84,0x38,0x05,0xd8,0x2e,0x7f,0xcf,0xe8, -0xbf,0x94,0xeb,0xd7,0xed,0x38,0x15,0x76,0xbe,0xf4,0xde,0xd7,0x60,0xd9,0xad,0xe8,0x07,0x51,0xeb,0x5e, -0xcf,0x5b,0x60,0xdf,0x6c,0x1a,0x48,0xdf,0x9b,0x1e,0x29,0xb6,0x16,0x1d,0x77,0x0d,0xe1,0xb5,0x81,0xaa, -0x4d,0x0f,0x95,0x99,0xa4,0x5a,0xa5,0x7d,0x55,0xbd,0xe2,0x90,0x9b,0x96,0xf5,0x59,0x60,0x92,0xf3,0x62, -0xde,0x86,0xa6,0xdd,0xf9,0x8e,0xad,0x7f,0xf3,0xb6,0x14,0xda,0xb2,0x71,0x76,0x8c,0x00,0x82,0x8d,0x2c, -0xfd,0x6d,0x69,0xdb,0x06,0x0f,0x2a,0x6f,0x1a,0xda,0xed,0x8d,0xe8,0xc9,0xff,0xd6,0xf4,0x5b,0xca,0xf8, -0x88,0x66,0xdb,0x25,0x71,0xbb,0x91,0xd5,0xc7,0x74,0x57,0xdb,0x8c,0x03,0xdf,0x56,0x72,0xd3,0x3b,0x3a, -0x6f,0x53,0x58,0x4b,0x37,0xbd,0x8c,0x60,0x13,0x81,0x75,0x88,0xe4,0x90,0x25,0x86,0xc6,0xf6,0x67,0x60, -0x1f,0x3a,0x91,0x5a,0x53,0xe1,0x9e,0xd4,0x50,0xd7,0x7a,0xd9,0x59,0xc9,0x2e,0xc7,0x13,0x13,0x33,0x4b, -0xef,0xa7,0x91,0xcf,0x09,0xea,0xf4,0x72,0xb9,0x48,0xea,0x94,0xc3,0xe6,0xa6,0x4d,0x68,0x2d,0x08,0xb7, -0x9a,0x0d,0x9b,0xc8,0x61,0x6a,0xbb,0xcf,0xb3,0x3d,0x99,0xb3,0x08,0x05,0xe5,0x3a,0x9d,0x35,0x8c,0x8e, -0x85,0xbd,0x65,0x47,0x58,0xa9,0x1b,0xb6,0xd1,0xe3,0x5e,0x76,0x6c,0x73,0xbe,0x10,0xe1,0x4f,0x1e,0x00, -0xc4,0xa8,0x43,0x70,0x4a,0x86,0x9c,0x33,0x87,0x04,0x1f,0xd6,0x3f,0x81,0xbd,0x79,0x02,0x57,0xc8,0x7f, -0x90,0xb2,0xa5,0x80,0x4b,0x00,0xb2,0x20,0xfc,0xd5,0x12,0xd4,0x64,0xb4,0x75,0x22,0xba,0x11,0x8e,0xd7, -0x61,0x3b,0x6a,0x4b,0xa0,0xd9,0xbd,0xdf,0x81,0x21,0xf1,0xb3,0x73,0x92,0x19,0x1c,0x9c,0x63,0x7b,0x7b, -0x48,0xe4,0xed,0x84,0x12,0x57,0x8e,0x91,0x6d,0x1a,0xf7,0xd1,0x48,0x5f,0x76,0xe6,0x26,0x3a,0xa8,0xda, -0x76,0x4d,0x44,0x13,0xd9,0x6d,0xa6,0x70,0x49,0xd8,0x3f,0x0c,0x17,0x71,0x6b,0xc7,0xcb,0x60,0x11,0x9b, -0x0e,0x0b,0x62,0xa7,0x70,0x6a,0x40,0x04,0x4c,0x0d,0x98,0x37,0xc6,0x17,0x6a,0xc7,0x49,0x4c,0x74,0xad, -0xc1,0x60,0x75,0x64,0x24,0x70,0x41,0x31,0x5d,0x19,0xa4,0x31,0x48,0xff,0x72,0x30,0x4d,0xb1,0x8e,0x1d, -0x8f,0x68,0x91,0x2f,0xf3,0x27,0xc9,0xa2,0x4a,0x19,0x0e,0x5b,0x7f,0x07,0x9b,0xc7,0x43,0x20,0x12,0x5c, -0xa6,0x97,0x45,0xf9,0x7e,0xbd,0xf6,0xf9,0x01,0x1d,0x07,0x76,0x0f,0x99,0xdb,0x29,0xe2,0x1c,0xf0,0x7a, -0x1c,0x24,0xe0,0x34,0xbe,0x71,0xc8,0x72,0x63,0xae,0xa0,0xe0,0x07,0x6b,0x27,0x6f,0x6a,0x64,0xa2,0x37, -0xab,0x46,0x6f,0xbd,0x03,0x86,0xf2,0xa6,0x37,0x3c,0x62,0xce,0xcf,0x9d,0x88,0x80,0x13,0x3d,0xba,0x7b, -0x7b,0xa7,0x50,0xc5,0xd2,0x23,0x18,0x91,0xa9,0x5c,0x23,0xd6,0x07,0xeb,0x63,0x60,0xb3,0x8f,0x9b,0xe8, -0x1c,0x30,0xbf,0x2c,0x81,0x49,0x16,0x6c,0x2c,0x1c,0xf8,0x50,0xd5,0x75,0xa1,0x67,0x05,0xcc,0x7f,0x81, -0x15,0xdc,0xd3,0x34,0x5d,0xd1,0x06,0x87,0x7e,0xcb,0x59,0x7c,0xec,0x73,0xbc,0x26,0x15,0xd0,0x80,0x5a, -0x03,0x23,0x07,0x6c,0xf0,0x34,0x34,0xc6,0x9c,0x1b,0x82,0xc9,0xfc,0x88,0x03,0x90,0xed,0xef,0x6f,0x74, -0xe1,0x6d,0xce,0xc9,0x6c,0xc5,0x56,0x7e,0x69,0x58,0x30,0xb7,0x50,0x34,0xe6,0x0e,0x6d,0x55,0xac,0x33, -0x1c,0xac,0xd7,0x50,0xf9,0x2b,0xa9,0x50,0x5f,0x58,0xa8,0x38,0x11,0xa9,0x3d,0x5b,0x8c,0x3b,0xa9,0x7b, -0xc6,0x79,0xb7,0xd8,0x84,0x88,0x88,0xbd,0x3d,0x23,0x3a,0xcf,0x40,0xd6,0x2f,0xf9,0xe9,0xe2,0xf1,0x49, -0x6f,0x76,0xbb,0x19,0xeb,0x1c,0x39,0x44,0x6b,0xcb,0x2a,0x48,0x67,0xcb,0x13,0x52,0xe4,0xee,0x39,0x8c, -0x76,0x94,0xf6,0x7f,0xa2,0xad,0x00,0x68,0x0a,0xcc,0x9a,0x59,0x16,0x52,0xe1,0xd6,0xa0,0x22,0xef,0x9e, -0xba,0x9e,0x0e,0x75,0xa1,0xed,0x80,0x4d,0xd6,0x77,0xbd,0xf5,0x2d,0x37,0x06,0xa8,0xec,0xd4,0x89,0x85, -0xa3,0xe3,0x2a,0xf7,0x58,0x35,0x4c,0xa7,0x9e,0x44,0xa8,0xf5,0xb0,0x97,0x48,0x34,0x55,0xc4,0x1d,0x6b, -0x68,0x8b,0xef,0xc9,0xe2,0xf3,0x82,0x6d,0x8f,0xef,0xcd,0xc2,0xa9,0xa7,0xe2,0xd9,0x52,0x36,0x08,0xbf, -0xda,0xce,0x02,0x64,0x63,0x67,0x4b,0x3e,0xee,0xbb,0x51,0xa8,0xb3,0x9a,0x7b,0x92,0x2f,0x03,0xb0,0x87, -0x1e,0x62,0xb6,0xfe,0xf9,0x6c,0x0f,0x43,0x95,0x13,0xb2,0x85,0xf7,0x84,0x07,0x37,0x51,0xde,0x31,0xb3, -0x58,0xc5,0x8f,0xeb,0x8e,0x45,0x49,0x3c,0x19,0x87,0x85,0xed,0x9b,0xc6,0x12,0x73,0xb6,0x19,0x1e,0x89, -0x30,0xdb,0x19,0x2e,0x8f,0x3d,0x78,0xbc,0xde,0xcd,0x71,0x58,0x5f,0xa4,0xb9,0x82,0x5e,0xc4,0x9e,0x9f, -0x2d,0x9d,0x5a,0xc8,0x29,0xc3,0xe4,0x38,0x6e,0x16,0xbd,0x89,0x94,0x6d,0x8f,0xa8,0x26,0x06,0x79,0xb8, -0x65,0xfb,0xb3,0x4f,0x72,0xd3,0x72,0xfa,0xf9,0x0c,0xe7,0x56,0x75,0x35,0x2e,0xa6,0x38,0xc8,0xce,0xfc, -0x4e,0xf9,0xc0,0xd2,0xed,0x8f,0x20,0x36,0x4e,0xd5,0xb1,0xb7,0xc9,0x56,0xc7,0xa5,0x06,0x69,0xd4,0x21, -0xaa,0x83,0x26,0x6e,0x6f,0xad,0xe2,0x21,0xab,0x80,0xbd,0xb5,0x0e,0x83,0xac,0x3a,0xaf,0x56,0xe1,0x8f, -0x89,0x3d,0x9f,0x22,0xae,0xea,0xc0,0xc3,0x3a,0xf0,0x66,0x52,0x70,0xc6,0x71,0x5a,0x9a,0xe2,0x01,0xf5, -0x8c,0x40,0x1d,0x2c,0xd6,0x6d,0x4a,0xdb,0x84,0xe8,0x55,0xdb,0x2e,0x56,0xb0,0x6b,0x35,0x85,0x2f,0x7c, -0x63,0xb3,0xdb,0x36,0xde,0x92,0x26,0x57,0x12,0x40,0xeb,0x34,0xb6,0xa8,0x6a,0x37,0x14,0xd8,0x19,0x9f, -0xbf,0xfc,0xfa,0x28,0x09,0x94,0x2f,0x60,0xa9,0x7a,0x89,0x3e,0x45,0xbd,0x70,0x6e,0x32,0x95,0x0a,0x1a, -0x8f,0x20,0xf0,0xd1,0xca,0x2b,0xe8,0xed,0x85,0x58,0xe4,0xc0,0x25,0xff,0x6c,0x9f,0xfb,0x62,0xc5,0x7a, -0xbf,0x60,0x7c,0xc6,0x68,0x3a,0x1f,0x1b,0x6f,0x08,0xe3,0xc8,0x93,0xa9,0x15,0xb3,0xe4,0x2c,0x98,0x64, -0x93,0x33,0xed,0x97,0x56,0xf8,0x09,0x6c,0x84,0xa9,0xe5,0xea,0x72,0x01,0xd6,0x25,0xf2,0x93,0xc1,0x20, -0xbc,0x3d,0x91,0x79,0x9a,0x5b,0x01,0xad,0x03,0x7c,0x5b,0x4a,0xc4,0x4a,0xbf,0x52,0xc2,0x66,0x60,0x9f, -0xd2,0xb9,0x37,0xf4,0x89,0x38,0xe6,0x76,0x94,0xeb,0x80,0xfb,0x05,0x3c,0xdb,0x12,0x76,0xcd,0xf6,0x3c, -0x87,0x0b,0xdd,0x99,0xaf,0x71,0xf4,0x53,0x9e,0xc9,0x7a,0x86,0x13,0x11,0x3b,0x4d,0xd9,0x8a,0x08,0xd1, -0xa7,0x79,0xbe,0xf5,0xbf,0xa2,0xaa,0x2f,0x11,0x32,0xfa,0xf4,0xb7,0xb7,0x65,0x72,0x8a,0x83,0xe0,0xe0, -0xf0,0x7e,0x8c,0x08,0x6b,0xa8,0xe2,0xa2,0xa7,0x8a,0xb9,0x1d,0x6c,0x5b,0x55,0x6e,0x5c,0x4f,0x96,0xd0, -0x2c,0xd8,0xc5,0xd0,0x41,0x8d,0x79,0x32,0xa9,0x80,0x6f,0x97,0x12,0x6f,0x4b,0xe7,0x8b,0xef,0x43,0xca, -0x31,0xd1,0x8b,0x55,0xed,0x2f,0x91,0x3b,0x66,0x4e,0x12,0x8f,0x6e,0x5d,0xc8,0x08,0x01,0x45,0x53,0x7f, -0xfa,0xd9,0x8c,0xcf,0x7b,0x85,0x8f,0xa8,0xb4,0xee,0xa8,0x66,0x34,0xaa,0xd1,0x2a,0x4c,0x9d,0xb1,0x60, -0x96,0xea,0xb6,0xaf,0xea,0x80,0x4e,0x6f,0x2b,0x4e,0x78,0xef,0xd6,0x84,0x65,0x30,0x29,0xa3,0x05,0x74, -0x71,0xf6,0xa2,0x52,0x97,0xb7,0x04,0x28,0x9b,0x34,0x5b,0x0e,0xc7,0x8d,0xce,0x68,0xac,0x11,0x10,0x78, -0xdc,0x62,0x56,0xf2,0x16,0x93,0x22,0xbd,0x52,0xc3,0x66,0x9a,0x96,0xde,0xf4,0x8b,0xd9,0x38,0x9b,0xd6, -0xa0,0x45,0xc4,0x4d,0x52,0x1d,0xc3,0x0a,0xe1,0x48,0x50,0x59,0x9b,0x08,0xc7,0x44,0x5a,0xf3,0xe9,0x67, -0xfb,0xe9,0x8c,0xbe,0xd3,0x6e,0xfe,0x21,0xf7,0x1c,0xdd,0x63,0x53,0x0f,0x42,0xf9,0xaa,0x46,0x5b,0xb1, -0x69,0x42,0x87,0x0f,0x21,0xe0,0x2c,0xee,0xa1,0xe6,0xfc,0xc6,0xa1,0x37,0x70,0x50,0x50,0xe2,0xae,0xa8, -0x7f,0x27,0x76,0x3f,0xa2,0xda,0xea,0x9d,0x1b,0x6a,0x31,0xd3,0x77,0x45,0x20,0x32,0x45,0x5e,0x5f,0x05, -0xe2,0x2d,0x11,0xa3,0x72,0x75,0x91,0xf6,0x19,0x70,0x75,0x82,0x07,0x22,0x76,0x75,0x19,0xeb,0xd8,0x79, -0xb4,0x57,0x75,0xe3,0x06,0x51,0x1f,0xdb,0x13,0x29,0xb0,0x71,0x6a,0xb7,0x18,0xa8,0xe2,0x88,0x24,0x24, -0x15,0x57,0xed,0x42,0xef,0x1f,0x4e,0xba,0xa5,0x44,0x79,0xb8,0xbf,0x5f,0x83,0xbb,0xb5,0x23,0xd7,0x83, -0x8a,0xd2,0xa2,0x81,0xbc,0xf5,0x28,0xc6,0xb1,0xe7,0x14,0x14,0x44,0xed,0x8c,0x60,0xac,0x75,0xea,0xb0, -0x50,0x8b,0x0d,0x7a,0xff,0xd0,0x6c,0xbe,0xec,0x04,0xc2,0xbb,0x2f,0xd0,0x6e,0x5b,0xb3,0x9c,0xa3,0x38, -0xe3,0x2f,0x53,0xb6,0x26,0xd0,0x4d,0x21,0xdb,0xa6,0x72,0x49,0x64,0x33,0x8d,0x53,0x4e,0x1d,0xa2,0x48, -0x53,0x52,0x63,0x65,0x6d,0x4d,0x63,0x75,0xa6,0x7a,0xce,0xc2,0x46,0xc4,0x5e,0x5b,0x3f,0xa3,0x93,0x66, -0x99,0xd3,0xc5,0xeb,0x24,0x3f,0x4f,0xd7,0xaf,0xd1,0x8f,0x29,0xf1,0x0e,0x6b,0x71,0xd9,0x5c,0xb3,0xdb, -0xff,0x77,0xaf,0x9f,0x05,0x4c,0xb3,0x45,0x3d,0xd4,0x4f,0x81,0x62,0x6b,0xcb,0xc9,0x81,0xf2,0x01,0x31, -0x75,0x21,0xae,0x97,0xea,0x72,0x78,0x95,0x94,0x08,0x50,0xb1,0xb7,0xf7,0x5c,0x9d,0x03,0x69,0x47,0x84, -0x51,0x5f,0x3b,0x8d,0xaf,0xe2,0x16,0x9a,0xa2,0x76,0x4c,0x51,0x30,0xc5,0xad,0xe9,0x44,0x54,0x55,0xc9, -0x39,0xbc,0x67,0x99,0x1a,0xf1,0xb9,0xff,0x3c,0x15,0x59,0xec,0x63,0x9d,0x34,0xb6,0xd9,0x03,0x87,0x1c, -0xd9,0xd4,0x97,0x77,0xa6,0x9a,0x76,0x53,0xee,0x9a,0xa7,0xa9,0x3b,0x9d,0x94,0x1c,0x95,0x33,0xee,0x9b, -0x58,0x4f,0x65,0xe3,0xa1,0x27,0x53,0xc5,0xea,0xcc,0x1c,0x62,0xd6,0xa9,0x94,0xcf,0xd0,0x11,0xb2,0x82, -0x2c,0x26,0xd5,0x84,0x5e,0x3c,0x0c,0x39,0xfd,0x0f,0x49,0x56,0x47,0xea,0xda,0x59,0x29,0xec,0x75,0xbf, -0x3b,0x9a,0xec,0xef,0xeb,0xac,0x39,0x29,0x4f,0x1e,0xce,0x02,0x36,0x49,0xcd,0x1d,0xc7,0x78,0x51,0x11, -0x8d,0xdd,0x4f,0xee,0x8f,0xd6,0xeb,0xa7,0xa9,0x33,0x9f,0xf3,0x34,0x9c,0x9e,0x43,0x6c,0xab,0x84,0x66, -0x9c,0x96,0xdb,0x17,0xab,0x76,0x22,0x58,0xe1,0xe5,0x12,0x01,0x68,0xd8,0x77,0x48,0x25,0x79,0x83,0x29, -0x0c,0xc0,0xc0,0x22,0x99,0xab,0x43,0x9e,0xf3,0x0a,0xe0,0xf7,0x1d,0x0c,0x0a,0xba,0x7f,0x73,0x5a,0x16, -0x8b,0xc5,0xc4,0x19,0x1a,0x5d,0x2c,0xed,0x42,0xf4,0x4d,0x17,0x42,0xee,0xd1,0xcb,0x17,0xca,0xfa,0xfb, -0x39,0x95,0x06,0x68,0x92,0x33,0xc6,0x6c,0xe9,0x24,0x14,0xe8,0x38,0xa0,0xc3,0x63,0x5c,0x9f,0xb4,0xb5, -0xc5,0x3a,0x90,0xa9,0x66,0x7a,0x7a,0xb0,0xfc,0xa1,0x38,0xb6,0xa2,0x20,0xc5,0xf6,0xd1,0x95,0x98,0x1e, -0x08,0x01,0xd8,0xf6,0x4d,0xa2,0x88,0x3f,0x91,0xa8,0xde,0x15,0x51,0xe1,0x0a,0x6a,0x30,0xce,0xdc,0x38, -0xa7,0x38,0xb1,0x3b,0x33,0x15,0xb5,0xde,0xd9,0x75,0x38,0x92,0x29,0xe3,0xac,0xb3,0x1c,0xda,0x04,0x16, -0x84,0x1d,0x8c,0xc0,0x9f,0x53,0x97,0x2c,0x88,0x20,0x76,0x15,0x59,0x6a,0x2e,0x2e,0x6c,0x41,0x70,0xce, -0xe0,0x2b,0x4a,0x0b,0x63,0x42,0x12,0xd4,0xec,0x17,0x40,0xad,0x4f,0x68,0x93,0x2b,0x75,0xe8,0xc2,0x0a, -0xb8,0xfb,0xfa,0x95,0x15,0x86,0x20,0x9b,0xa4,0xd1,0x62,0xa2,0x2b,0x12,0x44,0xab,0x89,0x38,0x59,0x86, -0x70,0xd9,0xd8,0x84,0x2f,0xfb,0xdc,0xc4,0x5b,0xea,0x58,0xf1,0x64,0xb6,0xef,0x77,0x07,0x96,0xb2,0x76, -0xbc,0x1c,0x22,0xd4,0xdb,0x61,0x68,0x9b,0x32,0x8a,0xb3,0x70,0x9f,0x94,0x76,0x2a,0x71,0x77,0x25,0xb8, -0x69,0xcb,0x1f,0xf1,0x06,0x15,0x62,0xc1,0x92,0x6f,0x43,0x9f,0xb8,0x9f,0xc4,0x75,0xa4,0x24,0xc4,0xe2, -0x48,0xd8,0x38,0x93,0x84,0x76,0xba,0x50,0x59,0xf0,0xd5,0x90,0xee,0x9d,0x65,0xe7,0xab,0x92,0xcf,0xe8, -0xac,0xa6,0x85,0x09,0x45,0x58,0xa5,0x75,0x47,0x32,0xa9,0x5d,0x4d,0x44,0x47,0x87,0x26,0x68,0x80,0xaf, -0x4e,0xb4,0xbd,0x20,0x9b,0x42,0x61,0xa2,0xa3,0x5c,0x12,0x7d,0x9a,0xd1,0x5c,0x33,0x8e,0xd5,0x4a,0x69, -0xd6,0x4a,0x54,0x06,0x6e,0x48,0xc4,0xac,0x1d,0x2a,0xda,0x12,0xc4,0xcb,0x74,0x83,0x22,0x7e,0xe2,0x54, -0x27,0x6a,0xf5,0x07,0x0e,0x40,0xce,0x83,0x4e,0xbd,0xe8,0x0c,0xc8,0x61,0xc5,0xb7,0x09,0x62,0x9b,0x92, -0xd6,0xeb,0xba,0x47,0x5e,0x48,0xcf,0x4c,0x92,0x7c,0x62,0x44,0xff,0xa8,0x6c,0x24,0x9a,0x80,0x2a,0x55, -0x71,0xec,0x82,0xb0,0x51,0xaf,0x4d,0xf2,0x08,0x70,0x0c,0x6d,0xd1,0x8f,0xa3,0x32,0x6a,0x4f,0x07,0x67, -0x99,0xf1,0xa9,0xc4,0xdc,0xd2,0x57,0x6e,0x24,0x5e,0xb0,0x83,0x71,0xcd,0x22,0x51,0xbb,0xc5,0xa8,0x53, -0xdc,0xea,0x82,0x50,0x94,0xa9,0x3b,0xe5,0x64,0x5a,0xcf,0x22,0x85,0xc7,0xe1,0xff,0x9e,0x8a,0x31,0x9f, -0xad,0x39,0x6b,0x76,0x64,0x15,0xa4,0xab,0x9c,0xc2,0x7a,0x72,0xb6,0xf1,0xed,0x5e,0xe2,0x85,0x6f,0xc5, -0x6a,0xf5,0x19,0xa4,0xe8,0xb6,0x49,0xab,0xd8,0xb0,0x26,0xf2,0x97,0xfd,0x16,0x67,0x8a,0x8b,0xa4,0x7a, -0x84,0xa0,0xef,0x1f,0xbd,0x64,0x9a,0x8e,0x21,0xda,0xdc,0xa9,0x50,0x0d,0xae,0x06,0xdf,0xbf,0x4a,0x95, -0xd9,0xf0,0x6b,0x7d,0xf1,0x42,0xab,0xde,0x6f,0x44,0xef,0x7e,0xf7,0x78,0xb3,0x3e,0x9e,0xea,0xeb,0x19, -0x94,0xee,0xcf,0x20,0xb1,0x7d,0xb0,0xff,0xaf,0x99,0x88,0x69,0x2d,0x15,0x64,0xa7,0x8e,0xaa,0x36,0xaf, -0x39,0x5a,0x3c,0xde,0xfa,0xe8,0xd5,0x57,0xf6,0xed,0x46,0xc2,0xd9,0x6f,0x99,0x7d,0xf4,0xa5,0x4c,0x4f, -0xf5,0x5c,0xcf,0x98,0x47,0xed,0x6f,0x82,0x9b,0xd7,0x3a,0xe8,0x98,0x42,0xfa,0xf8,0xe5,0xb6,0x7c,0x5f, -0x75,0xf2,0xfd,0x65,0x6b,0xc6,0xaf,0xdc,0x8c,0x65,0xeb,0xb4,0x74,0xaf,0x9d,0x72,0x5a,0xc0,0x8c,0xa2, -0x81,0x43,0x7c,0x0e,0xb8,0xf7,0x36,0x56,0x73,0xcd,0x7c,0x16,0x78,0x40,0xb0,0x99,0x8d,0x98,0x9d,0xb7, -0x91,0xd7,0xac,0x0a,0x07,0x8f,0x7d,0xc8,0xbc,0x64,0xa3,0xa8,0xdc,0x7d,0xa5,0x5e,0x85,0x9e,0xea,0x4b, -0x98,0x89,0x55,0x5e,0xa0,0x22,0xf6,0xe5,0x26,0xe0,0x8b,0x4c,0xd8,0x84,0xd9,0x4d,0xbf,0x8c,0x71,0xc1, -0x4c,0x59,0x38,0x62,0xcb,0x1d,0xe3,0x0e,0x8f,0x66,0xec,0x7b,0xa2,0x1b,0x70,0xe9,0x92,0x12,0xf7,0x7d, -0x41,0xa4,0xf1,0x42,0x62,0xdc,0x40,0x79,0x4f,0xdb,0xc8,0x2b,0xde,0xd9,0x3b,0x75,0x80,0x01,0x81,0x51, -0xe7,0xab,0x8b,0xee,0x51,0x5f,0x68,0x05,0x1f,0x99,0x2c,0x76,0xed,0xb5,0x64,0xa9,0xc3,0xcb,0x07,0xd1, -0x93,0xb4,0x1d,0x35,0x5e,0xbb,0x5e,0x49,0xf4,0x87,0x66,0xe5,0x29,0xa4,0x4b,0xdd,0x67,0xf4,0xb9,0x45, -0x6f,0x9c,0x30,0x92,0x79,0x7c,0xb1,0xf5,0xbd,0xec,0xe8,0x1f,0xae,0x1b,0x87,0xa9,0xdf,0x88,0x4b,0x5d, -0x1d,0x76,0x0f,0x19,0xf2,0x06,0x3d,0xd1,0x3f,0x65,0x5b,0xa1,0xe6,0xbb,0x45,0xa9,0x39,0x67,0x7a,0x42, -0x2b,0x3a,0xd5,0xac,0xfb,0x7d,0x95,0xae,0xd2,0xfe,0x3d,0x0a,0x4d,0x6c,0xec,0x5d,0x62,0x0e,0xf5,0x73, -0x76,0x0d,0x2f,0x71,0xfe,0x08,0xe8,0x24,0x6a,0xf6,0xa0,0x15,0x10,0xc8,0x33,0x16,0x58,0x27,0x94,0x39, -0x27,0xb3,0x96,0x89,0x63,0xfa,0x40,0x7c,0x44,0x54,0x36,0x1a,0x86,0x12,0xc4,0x92,0xd6,0x72,0xda,0xad, -0x17,0xf1,0xe0,0xb1,0xaa,0x82,0x82,0xd2,0x39,0x67,0x80,0xb9,0x95,0x2c,0x28,0x2b,0xd8,0x5f,0x88,0xe8, -0x24,0xc6,0xd6,0x1e,0xc9,0x7e,0xe1,0x74,0x38,0x7e,0x54,0x92,0x38,0xb1,0x4f,0xb7,0xe7,0x30,0xd7,0x6c, -0x72,0xda,0x8c,0x61,0xe8,0xa9,0xc5,0xbc,0x70,0x30,0xe7,0x45,0xd4,0x64,0x59,0xee,0xef,0x8b,0x19,0x09, -0xea,0x12,0x2b,0xc3,0x3c,0x0d,0x04,0x65,0x7f,0x0b,0xa8,0x7c,0xa6,0xc5,0x05,0x2b,0x6f,0xe8,0xb8,0xab, -0x78,0xb5,0x84,0x0e,0xb8,0x30,0xea,0xa1,0x95,0x8c,0xc5,0xcc,0x4a,0x00,0x3e,0x17,0x43,0x86,0x60,0x55, -0xb6,0x3f,0x92,0xb3,0x1a,0x00,0x4e,0xe1,0x8d,0x1b,0x52,0x24,0x43,0x91,0x0b,0x69,0x34,0x1d,0x9e,0x87, -0x37,0xa2,0x64,0xb8,0x45,0xf2,0xdb,0x16,0x1c,0xd8,0xb4,0x6a,0x5a,0x9b,0x01,0xcf,0x67,0x12,0x39,0xae, -0x43,0xbb,0xfa,0x46,0x4b,0x2a,0x7b,0x4f,0x2b,0x10,0x7b,0x0c,0x34,0x7c,0x89,0x21,0x8c,0x5e,0x0c,0x73, -0xf4,0x69,0x7b,0xfa,0x1f,0xe5,0x13,0x33,0xc6,0x9a,0xfe,0x19,0x34,0x55,0xc3,0xb5,0x44,0xbd,0x53,0xbf, -0x35,0x45,0xcc,0x6a,0x1b,0xb7,0xa6,0x83,0x5a,0x18,0xa1,0x1a,0xcb,0x54,0xcc,0x7c,0xf5,0x08,0x62,0x4d, -0xb3,0x01,0x84,0x35,0x47,0x9a,0xa5,0xd4,0x33,0x4f,0x6f,0x5f,0x8f,0xfd,0xb9,0x9c,0x2e,0xd2,0xa4,0xfc, -0xe7,0xad,0x19,0xa9,0xd9,0x29,0xd3,0x1f,0x3e,0xbd,0x7d,0xa2,0x26,0x9b,0xe9,0x39,0x0c,0xb3,0x96,0xc0, -0x43,0xb6,0x10,0x9a,0xf9,0xb6,0xf9,0x4c,0x65,0xaf,0x83,0xfd,0x7d,0x5a,0x7e,0x99,0x73,0xd4,0x2b,0x42, -0x84,0x7b,0xdb,0x30,0xcb,0x72,0xcb,0x10,0xca,0x88,0xb0,0x3b,0x82,0x5a,0xa1,0x12,0x84,0x50,0x13,0x08, -0x44,0x22,0x0c,0x53,0x67,0xde,0x2a,0x40,0x5f,0x9e,0x9a,0xd8,0x2c,0x06,0x83,0x50,0xdd,0xf1,0x64,0xac, -0x9a,0xe3,0x45,0xe5,0xdb,0x82,0xa2,0xda,0x88,0x27,0x7e,0xe0,0xb0,0x01,0xfb,0xb3,0x09,0xf8,0x8c,0xf9, -0xdd,0xe3,0xe1,0x3a,0x38,0x9e,0x0f,0xe8,0x66,0x9a,0x3e,0x9e,0xf1,0x0b,0xba,0x5d,0x07,0x07,0x2a,0x22, -0x67,0x78,0xa7,0x15,0xd0,0x42,0x87,0x70,0x08,0xe2,0x75,0xe0,0x7b,0x83,0x1f,0x38,0x9c,0x08,0x0c,0x65, -0xff,0x32,0xbb,0x6b,0xc2,0x32,0x7c,0x9d,0xc6,0x53,0xef,0x6d,0xb1,0xa4,0xdb,0xd7,0xb0,0x82,0xa7,0xdf, -0xaf,0x8b,0xba,0x2e,0x2e,0xe9,0xe2,0x79,0x7a,0x56,0x7b,0xb3,0xf0,0x97,0x2d,0xb8,0xfd,0x29,0xc8,0x15, -0xac,0x16,0xa0,0xea,0xe1,0xd3,0x4d,0x55,0xbf,0x5f,0x30,0x98,0x3e,0x47,0x75,0x59,0x7b,0x3d,0x4f,0x79, -0xa6,0x19,0x13,0xa9,0x16,0xa0,0x58,0x88,0x63,0x8b,0xc9,0x0f,0x09,0x79,0x85,0x7b,0xea,0x5b,0xe8,0x77, -0xff,0xe8,0x1e,0x60,0xed,0x40,0xe4,0x37,0x32,0x94,0x85,0x9c,0x1c,0x12,0x44,0xe7,0x53,0x15,0x40,0x94, -0xf3,0xe6,0x92,0x4e,0x10,0xe0,0x94,0x89,0xe8,0x69,0xc4,0x7c,0xa6,0xcc,0x81,0xfd,0xb5,0x95,0x1a,0x19, -0x59,0xe7,0x8d,0x1f,0x53,0x14,0xe4,0x92,0x88,0xea,0xa2,0xb8,0xea,0x51,0x10,0x29,0x75,0x09,0x6f,0x70, -0x17,0xd9,0xbc,0x4f,0xbf,0x24,0x49,0xa0,0xb1,0x28,0xce,0xcf,0x17,0x7d,0x6b,0xc4,0x3b,0x91,0x18,0xdc, -0x36,0x5b,0xa0,0x18,0x03,0x14,0xeb,0x2b,0x9b,0x41,0xe4,0xaf,0xaf,0xdb,0x2b,0xf3,0x17,0x59,0x91,0x6c, -0x55,0xca,0x17,0xfa,0x4b,0x73,0x2f,0x5f,0x6f,0xcc,0xf4,0xfb,0x4e,0xb1,0xb8,0xda,0x9f,0x6f,0xcd,0x1e, -0x7e,0x6c,0x2f,0xfd,0x3d,0xbd,0x72,0x6d,0xae,0x5d,0xc3,0x84,0x80,0xd2,0x7c,0x83,0xcf,0xef,0xac,0x8f, -0x0f,0x28,0x8b,0x5f,0x93,0x77,0xc9,0x3a,0x3d,0xbd,0x4c,0x82,0xea,0xb4,0xcc,0x96,0x35,0xbd,0xfe,0x89, -0xba,0x50,0xfc,0x82,0xa3,0xe9,0x61,0xe8,0x69,0x70,0x5b,0x1d,0xdf,0x27,0xfe,0x54,0x5f,0x7d,0x0a,0xc7, -0x8e,0x06,0xd6,0x16,0x06,0xc3,0x69,0x32,0x97,0x8f,0xd8,0x8b,0x45,0xde,0xab,0xcb,0x19,0x9d,0x54,0x17, -0xd1,0xf4,0x9e,0x79,0x79,0x44,0xf7,0xe7,0x65,0xb1,0x5a,0x4a,0x32,0x73,0x67,0x7d,0x51,0x97,0xce,0x07, -0xf5,0x49,0x31,0x7f,0xaf,0x32,0xe5,0x4b,0x3b,0x29,0x15,0xfc,0x59,0x3b,0xe9,0x51,0x5d,0xaa,0xe4,0xe5, -0xfd,0x9e,0x6f,0x7e,0x51,0xae,0x12,0xd1,0x74,0x04,0x34,0x07,0xcf,0x9b,0x6d,0xc6,0x3f,0xd1,0xc4,0x5f, -0xd6,0x5c,0x93,0x58,0xae,0xa9,0x23,0xa8,0x4f,0x86,0xfc,0x35,0x1e,0xd5,0x67,0x45,0x51,0xe3,0x42,0xd7, -0x98,0xaf,0x13,0x11,0xe8,0xfd,0xc4,0x52,0xa8,0x64,0xce,0x5f,0x5c,0xf0,0xed,0x9c,0xc7,0xec,0x9f,0x18, -0x98,0xf5,0xde,0x27,0x93,0xe3,0xab,0xc1,0xf8,0x60,0xbc,0xdb,0x51,0xe3,0xe5,0xa9,0x72,0xbb,0xd1,0x4b, -0xee,0x49,0x99,0x9c,0xb3,0xff,0x0d,0xce,0x77,0x2e,0xe6,0xaf,0x49,0x6b,0x5c,0x74,0xe6,0xd9,0x3b,0x8f, -0xdd,0xe3,0xba,0xaf,0x34,0xac,0x70,0xde,0x0f,0x2b,0xcc,0x73,0x07,0x34,0xb1,0xf5,0x5a,0x23,0x2b,0x87, -0xe6,0xaa,0x9b,0x46,0x41,0x0d,0xd7,0x50,0xd6,0xbb,0x15,0x04,0xff,0x21,0x7e,0xe6,0x0f,0x17,0x44,0x34, -0xe0,0x01,0x88,0x5f,0x76,0x00,0xa1,0x15,0xd7,0xba,0x33,0xf8,0x2f,0xda,0x35,0x3d,0xac,0x1d,0xcf,0x1b, -0x1d,0x08,0xe6,0xfe,0x35,0x8d,0x9e,0xbe,0xf6,0x50,0x44,0x5e,0x70,0xfe,0x0f,0xe5,0xb3,0x78,0x77,0xb7, -0x5d,0x50,0x93,0xb5,0xe3,0x17,0xe3,0xcb,0x4a,0xfa,0x3b,0xf7,0x7b,0x3b,0xb2,0xc4,0x3f,0xb0,0x40,0x7e, -0x4b,0xdf,0x1f,0x84,0xff,0x52,0x2b,0xed,0xb2,0x58,0x55,0xe9,0x7a,0x59,0x64,0x10,0x46,0x73,0x50,0x2c, -0xaa,0x05,0xa5,0x5d,0xad,0xe7,0x34,0x4a,0xf4,0xa7,0x58,0x06,0xeb,0x53,0x3a,0x64,0xfc,0x76,0x10,0xa6, -0x35,0xbe,0x99,0xfe,0x3c,0x24,0x5a,0x8e,0xfd,0x61,0xe8,0x0f,0x11,0x9d,0x87,0x05,0xd3,0x70,0x5c,0xae, -0xe3,0x9b,0xf3,0x45,0x71,0x92,0x2c,0x00,0x1c,0xd7,0x36,0x54,0x74,0xd0,0x8a,0x1a,0x37,0xd7,0x06,0x2d, -0x28,0x7c,0x67,0x58,0xdf,0x40,0x80,0x7d,0xf8,0xb0,0x44,0xe7,0x51,0x60,0xd2,0x95,0x62,0x73,0x13,0x02, -0xcc,0x5e,0x3d,0x01,0xb4,0x88,0xf1,0x9b,0x61,0xe6,0x71,0x9b,0x89,0xe8,0xdf,0xa1,0x15,0xa2,0x31,0x3e, -0x5f,0x65,0x73,0x58,0x4e,0xf0,0x05,0x68,0x3d,0x7e,0x07,0x83,0x20,0xf4,0x57,0xf1,0x3b,0x69,0x42,0x05, -0x61,0x60,0x73,0xc7,0xd8,0x2e,0x7e,0x42,0xf7,0x52,0xa8,0x88,0x0a,0xf5,0x9d,0x23,0xe5,0x56,0x64,0xb3, -0x07,0x27,0xeb,0x5c,0xb4,0xd5,0x9c,0xe3,0x90,0xa6,0xd8,0xf9,0x79,0x5a,0x72,0xd8,0x63,0x89,0xdf,0x3c, -0x31,0xef,0xb0,0xe7,0xb0,0xbb,0x89,0xde,0x20,0x2c,0x2d,0x88,0x82,0xbb,0xc7,0x92,0xe1,0x53,0x03,0x31, -0x98,0xb6,0x34,0x84,0x96,0x78,0xb8,0x68,0xc4,0x21,0x0b,0xb0,0x0a,0x55,0x9c,0xd6,0x62,0xed,0x5e,0x4f, -0x17,0xb3,0x40,0x01,0xec,0x9c,0xc7,0x15,0xac,0xcd,0x2f,0x62,0xbf,0x9a,0xde,0x53,0x50,0x78,0xca,0x25, -0x6f,0xa8,0x7d,0xf2,0x68,0x92,0x33,0x12,0x8e,0xa9,0x19,0xfb,0x34,0x25,0x8b,0xe9,0x7c,0x06,0xb3,0x3d, -0xca,0xc5,0x87,0x76,0x17,0x9c,0xf8,0x39,0xad,0x48,0x9c,0x7b,0xa3,0xb3,0xe1,0x09,0xf5,0xbd,0xc2,0xd3, -0x99,0x87,0xdb,0x3f,0x3e,0x8d,0xad,0xb3,0x12,0xbb,0xe9,0xce,0xc3,0x82,0x7a,0x85,0x73,0x39,0x17,0x99, -0x43,0x19,0xaa,0x41,0x8e,0xf2,0x10,0x83,0x14,0xc9,0x98,0x85,0x7a,0xb8,0xa3,0xcc,0x0d,0xee,0x24,0x83, -0xbf,0xc5,0x61,0x47,0xf4,0x1d,0x98,0x01,0xb4,0xaa,0xa9,0x87,0x4f,0xd3,0xe8,0x42,0xf9,0x1c,0x0e,0xb1, -0xbf,0xd3,0x19,0xde,0x5f,0xc6,0x2b,0xaa,0x1f,0x86,0x57,0xae,0x60,0xb5,0xb3,0x34,0x0d,0x7c,0x58,0xac, -0x72,0x04,0x5c,0x3e,0x03,0x99,0x58,0x2d,0xf7,0xf6,0xd4,0x85,0x91,0x13,0xd3,0x04,0x4e,0x00,0x2d,0xb4, -0x7b,0x08,0x5b,0xb5,0xb6,0x44,0x1c,0x3a,0x96,0x8e,0x94,0x7c,0xce,0x51,0x62,0xcf,0xf0,0x02,0x7d,0x8d, -0x5f,0x9d,0xdd,0x69,0x10,0x9e,0xea,0x59,0xae,0x27,0xad,0xfb,0x20,0x96,0xfe,0xa0,0x0c,0xb2,0xc9,0x52, -0x9b,0x51,0xb5,0xea,0x4b,0xdc,0xdf,0x88,0xb2,0x8a,0x96,0x3a,0x18,0x62,0x68,0x46,0x44,0x96,0x29,0x9a, -0x69,0x9d,0x82,0xff,0xcc,0x72,0x6d,0x84,0x45,0x7b,0x7b,0xee,0xea,0x65,0x93,0x37,0xb3,0xa8,0xb4,0x5f, -0xce,0xc7,0x4e,0x5d,0x60,0x76,0xfd,0x77,0x66,0xaf,0x8e,0xf2,0x78,0xcb,0x04,0x2e,0x3f,0x30,0x81,0x65, -0x1e,0x70,0xb1,0x55,0x5c,0x31,0x2a,0x64,0x0b,0x77,0x0f,0xa1,0xe7,0xbc,0x81,0x9e,0x4a,0x08,0xc7,0x36, -0x89,0x86,0x77,0x11,0xfb,0x2e,0xc0,0x89,0xde,0xc7,0x15,0x70,0xf8,0x20,0x5f,0x8a,0x97,0xba,0x7d,0x05, -0xab,0x0d,0xe3,0x25,0x98,0xc3,0x5d,0xcc,0xdb,0x5d,0xf8,0x4d,0xeb,0x05,0xb0,0x5e,0x33,0x0b,0x8f,0xc1, -0xe5,0xe7,0x32,0xfa,0x15,0x20,0xcf,0x64,0x1a,0x9f,0x0e,0xcd,0x2c,0xa6,0x6a,0xd2,0xd4,0x2a,0x39,0x5d, -0x65,0x70,0x84,0x7d,0xef,0xee,0x5d,0x4f,0x42,0x71,0xed,0x36,0xcf,0x79,0x66,0xeb,0x89,0x52,0xc0,0xde, -0xce,0xfe,0xa6,0x35,0x73,0xf6,0xf7,0x69,0x5e,0xca,0xa4,0xc0,0x54,0x97,0xab,0x66,0x72,0x06,0xe3,0x84, -0xea,0xb3,0x6c,0xa4,0x61,0x67,0x54,0xb5,0xa4,0x9c,0x13,0x5f,0x8d,0xe4,0xfa,0x5a,0x7f,0x70,0x11,0x1a, -0xea,0xa9,0x56,0xc8,0xb9,0x3e,0x0a,0x4b,0xb8,0xa1,0x94,0x66,0x94,0x49,0xa2,0x8f,0xf7,0xbc,0x1c,0x1b, -0xc0,0xd3,0x39,0xf8,0xe3,0x55,0x60,0xc6,0xd3,0x1c,0xa5,0xe7,0x03,0x4c,0x0f,0x9e,0xae,0x34,0x97,0xc7, -0x1d,0x81,0xea,0x4a,0x66,0xa6,0x49,0xef,0x49,0x39,0x3b,0x32,0x31,0x3d,0x88,0x70,0x35,0xd9,0xed,0x77, -0x54,0xd3,0xb0,0x0c,0xcd,0x5c,0x3a,0xcb,0x10,0x06,0x38,0x5c,0xf1,0xd1,0x47,0x44,0x2e,0xed,0x53,0x36, -0x40,0xcd,0x7c,0xb5,0x20,0xc4,0xef,0x4a,0x97,0xc7,0x66,0xcf,0xd3,0x4a,0xbc,0xbf,0x79,0x76,0x9d,0x76, -0x67,0xa9,0x79,0xad,0xce,0x16,0x2b,0xf8,0xc9,0x54,0x44,0xfa,0x0f,0xc7,0xf5,0x51,0xbb,0x2c,0xf6,0x4d, -0x5b,0xc1,0x57,0xd5,0xbc,0x51,0xd0,0xde,0x55,0x33,0xc1,0x19,0x5c,0x48,0x4e,0xab,0x34,0x2b,0x96,0x65, -0xfa,0x48,0x35,0x1a,0x61,0x59,0xad,0x5b,0xcb,0x73,0xa1,0x92,0xe1,0x92,0xa5,0x94,0x34,0x95,0x54,0x74, -0xa8,0xb2,0x93,0x22,0xa0,0x2c,0x5c,0xe5,0xfc,0x8c,0xce,0x2d,0x54,0x1f,0xd8,0x77,0xd1,0x8c,0xcd,0x2a, -0x68,0x79,0x92,0x73,0x46,0x2c,0x7a,0x53,0x17,0xc4,0x48,0x41,0xb1,0xcb,0x3b,0x3b,0x7d,0xbf,0x2a,0x61, -0x0c,0xae,0xea,0x96,0x0d,0xa9,0xae,0x97,0x21,0x40,0x4e,0x68,0xa7,0xcf,0x4c,0x31,0x1c,0x24,0x4c,0x67, -0xf7,0xec,0xf2,0x32,0x9d,0x67,0xc0,0xaf,0xed,0xcd,0xb7,0x1a,0x96,0x66,0x75,0xf0,0x17,0xcd,0xad,0x72, -0x98,0x77,0x56,0x8f,0x5f,0xa9,0x52,0x68,0xae,0x20,0xb6,0xfd,0x10,0x7b,0x0f,0x31,0x15,0xf8,0xa1,0xf3, -0xbe,0xef,0x77,0x06,0xa6,0x30,0x0b,0x75,0x26,0xf6,0xeb,0xf2,0x3d,0xac,0x13,0x54,0x7d,0x03,0xb5,0x79, -0xab,0xe6,0xac,0x2c,0x49,0x26,0x16,0x67,0x05,0x51,0x00,0x31,0x6b,0x71,0xa9,0x8d,0x90,0x7d,0xf1,0x9e, -0x80,0x6d,0xba,0xf0,0x71,0x44,0xbf,0x2a,0x96,0x6d,0x59,0x6d,0xf4,0x2d,0xd5,0x20,0x8d,0x57,0x51,0xd5, -0x7a,0xc0,0x60,0x00,0x6c,0xdf,0x3b,0x03,0x18,0xea,0xe2,0x58,0x51,0x21,0xfd,0xb9,0x5d,0x1e,0xce,0xb3, -0x9c,0xed,0xb0,0x6b,0x97,0x1e,0xd0,0x64,0x06,0x9a,0x13,0x86,0x09,0xd3,0x6a,0x85,0xe8,0xdd,0x96,0xbc, -0x1b,0x48,0x9f,0xc4,0x20,0xda,0x80,0x3b,0xe9,0x50,0x10,0x7d,0xee,0xc7,0x87,0x4a,0x0d,0xba,0x00,0xbf, -0x03,0x07,0xbf,0x45,0xbc,0x70,0xbc,0x00,0xf8,0x24,0xa8,0x5c,0x81,0xed,0x6c,0x75,0xae,0xbb,0x0d,0x4c, -0xd0,0xc2,0x44,0xd5,0x60,0xb5,0xba,0xda,0x55,0x94,0x01,0x39,0x51,0x75,0x01,0xc8,0x59,0x71,0xb0,0x58, -0x78,0xcb,0xe6,0x70,0x45,0x2e,0x0d,0x9d,0x03,0xfe,0x46,0x68,0x04,0x5d,0x89,0x40,0x4d,0xe3,0x07,0x5e, -0xb2,0x16,0xbf,0x80,0xf3,0xaa,0x78,0xb1,0x29,0x48,0x33,0x7f,0xc1,0x36,0xc6,0xda,0xff,0x53,0xde,0x29, -0x24,0xf4,0x85,0x41,0x42,0x27,0x3a,0xcf,0x59,0x16,0x06,0xd0,0xa6,0x30,0x24,0xb2,0x52,0xe8,0x24,0x98, -0x13,0xd1,0xa2,0x19,0x8b,0x62,0xd3,0x44,0xfe,0x95,0xd5,0xb9,0x3a,0xaa,0x3f,0xf8,0x55,0xad,0xc4,0xfe, -0x2b,0x06,0x55,0x61,0x5e,0x1b,0x73,0xa5,0x35,0xb2,0xfd,0xda,0x56,0x6a,0x04,0x53,0xdd,0x46,0xe9,0x1b, -0xa6,0xe1,0x0d,0x31,0xfc,0x97,0xa9,0xd6,0xb4,0xb6,0x35,0xaf,0xac,0xeb,0xec,0x98,0x74,0x59,0xe7,0x3c, -0xad,0x1e,0xc1,0xda,0xc8,0xf2,0x64,0xc1,0x05,0x18,0x29,0x77,0xdf,0xbb,0x4d,0xf4,0xd1,0x9f,0x77,0xde, -0x4c,0xd3,0x59,0x4b,0x0b,0xbc,0xb5,0xb1,0x4a,0x42,0xf9,0x81,0xe6,0x5d,0x95,0x59,0xad,0xaf,0x95,0xf2, -0x99,0x45,0x12,0xb0,0x78,0xee,0x77,0x06,0x9b,0x0a,0xb3,0xc9,0x7a,0xbd,0x49,0xca,0xa1,0x45,0x75,0xbf, -0xb2,0xde,0x4c,0x91,0x8b,0xe8,0x06,0x96,0x10,0x80,0x27,0xfc,0x7a,0x75,0xa2,0xb4,0xd8,0x0a,0x76,0xed, -0x46,0x9d,0x03,0x7a,0xfa,0x81,0xe6,0xf6,0x43,0xa0,0x58,0x89,0x33,0x18,0x52,0x3b,0x7d,0x71,0x26,0xa8, -0x6b,0x21,0xc2,0x6e,0x38,0xfc,0x8b,0xc7,0x6f,0xb2,0xdc,0xdb,0x84,0x27,0x8b,0x55,0x79,0x5b,0x11,0xb1, -0x5d,0x04,0x12,0x3b,0x25,0xe0,0xc1,0xf6,0x02,0x0a,0x3a,0x73,0x43,0xbe,0x4a,0x6b,0x73,0x5b,0x11,0x9e, -0x96,0xdf,0xb0,0x24,0x1f,0x59,0x0a,0x55,0x10,0x7d,0x38,0xbe,0x04,0x2c,0x85,0xec,0x8b,0xea,0x10,0xef, -0x54,0x80,0x93,0xa8,0x1a,0x18,0x51,0x46,0xbf,0x8f,0x8f,0x22,0x4b,0xa1,0x97,0xf0,0x56,0x7e,0x92,0x12, -0x45,0x48,0x25,0x78,0x61,0x74,0x63,0xd3,0x45,0x77,0x73,0xd7,0x24,0x39,0x55,0xf4,0x11,0x14,0xcb,0x99, -0x64,0x12,0x50,0xd2,0x7e,0x32,0x94,0x42,0xf9,0x94,0x6d,0xbe,0xa3,0x32,0x37,0xca,0xfc,0xc9,0xf0,0x33, -0x1d,0x1b,0x11,0xe7,0xad,0x7d,0x26,0xe8,0x79,0xec,0xd7,0xda,0xa0,0xaa,0x9b,0x97,0x23,0xbe,0x76,0x7d, -0x8c,0x25,0xf5,0xc4,0x67,0xd2,0x5b,0x1b,0xf7,0x5a,0xb7,0x05,0xda,0xd3,0x96,0x2d,0x3d,0x24,0x99,0x3c, -0xc8,0x2a,0xb5,0xf5,0xbc,0x92,0x8d,0x28,0x9d,0xc7,0x06,0x6d,0xc3,0x3c,0x5a,0xaf,0x1b,0x8d,0x68,0xe7, -0xa5,0xb4,0xa6,0xe9,0x1f,0x6c,0x6d,0x93,0xab,0xe8,0xad,0x2a,0x50,0x76,0x78,0x3d,0x58,0x7b,0x7b,0x9f, -0xc9,0x56,0xc1,0x77,0x76,0xac,0x1c,0xf5,0xa4,0xd9,0x1e,0x22,0x33,0xc0,0x32,0x31,0x1c,0x8e,0x21,0x75, -0xef,0x25,0x09,0x43,0xec,0xa4,0x73,0x93,0xc4,0xb9,0x57,0x82,0x4a,0xe9,0x00,0x18,0x47,0x36,0x27,0x51, -0xf1,0xce,0x52,0xde,0x50,0x75,0x76,0x99,0xbe,0xa9,0x93,0xcb,0x65,0x2c,0x1d,0xaa,0x6f,0x99,0x75,0xcd, -0x21,0xc3,0xe4,0x7d,0x44,0x14,0x28,0x16,0x2d,0xe0,0x4d,0xa9,0x45,0x0e,0x58,0xe3,0xdd,0xa5,0xba,0xf1, -0x8d,0xe5,0x4b,0x1e,0xe9,0xf7,0x61,0x77,0x28,0xa8,0x13,0xfb,0xd8,0x28,0x7e,0x7c,0x0b,0x3b,0xc4,0xef, -0xdf,0x64,0x97,0x2b,0x6e,0x3e,0x8c,0xdb,0x5c,0x2e,0xa3,0x6b,0xee,0xdf,0x9d,0x30,0xe3,0x6d,0xb3,0xe3, -0x2a,0xc4,0xbe,0xaf,0xde,0x9a,0x42,0x18,0x30,0xb1,0xc5,0xca,0x10,0x2d,0x74,0x39,0x99,0xff,0xa4,0xdc, -0x6e,0xab,0x6e,0x29,0xb9,0xc3,0x31,0x49,0xd1,0x7d,0x5d,0xf4,0x9f,0xd4,0xe1,0x96,0x2e,0xfe,0x40,0x65, -0xfa,0xbe,0xf4,0xd5,0x04,0xeb,0x56,0x76,0xd3,0xb8,0xca,0x26,0x8b,0xfa,0x1f,0xe9,0x7b,0xec,0x46,0x27, -0xbc,0x6d,0xb0,0x97,0xf9,0x29,0xd6,0xfa,0xc2,0x6c,0x61,0x17,0xb0,0x19,0x9d,0xbf,0x2d,0x56,0x8c,0x6e, -0x86,0x27,0x75,0xb9,0x50,0x5f,0xcd,0xd3,0x3a,0xc9,0x16,0xb8,0xe2,0xb1,0x78,0x45,0x87,0x74,0xfe,0xe8, -0x92,0x9e,0xab,0x24,0x54,0x70,0xfa,0xa3,0xbe,0xf8,0x09,0x17,0xac,0x69,0x55,0x6f,0xdf,0x65,0xe9,0x15, -0x7e,0x3d,0x04,0x40,0xf6,0x54,0x79,0x1c,0x09,0x19,0xd7,0xbf,0x49,0x22,0xfa,0xd1,0x4f,0x14,0x2c,0xa4, -0xb9,0x92,0x0a,0x2d,0x32,0x2a,0xfc,0xc7,0xe6,0x92,0x8b,0x29,0xce,0xce,0x68,0xeb,0xfe,0xb1,0xb9,0xe4, -0xa7,0x4a,0xfe,0xf8,0x6c,0x6e,0xdd,0xf0,0x96,0x83,0x8a,0x9d,0x96,0x69,0x9a,0xff,0xd8,0x5c,0xf2,0x17, -0x42,0x15,0xac,0xf6,0xd7,0x85,0x0e,0xb0,0xc5,0x37,0xe6,0xf9,0xd5,0x45,0xd6,0x77,0xb2,0x8b,0x35,0x87, -0xea,0x62,0xcb,0xa7,0x43,0x4e,0xbf,0xb7,0xf7,0x0f,0x03,0x7f,0xc9,0xf0,0x5a,0x13,0x65,0x69,0x6e,0x42, -0x42,0x4f,0x9a,0x4b,0xa2,0x51,0xa6,0x2f,0xcc,0xf7,0xb6,0x95,0xcf,0xbf,0x5a,0x79,0x1d,0xee,0xd5,0x80, -0x6a,0xa2,0xbf,0x9f,0x45,0x9f,0xd3,0xdf,0x7b,0xd1,0x28,0x52,0x1f,0xaa,0x69,0xc0,0xa4,0x42,0x71,0x75, -0x96,0x0f,0x35,0x0b,0x6b,0xb1,0x02,0xcb,0xc8,0xe3,0x6b,0xda,0x3d,0x4a,0x2f,0xe4,0xcb,0x45,0x9a,0xbc, -0x4b,0xf5,0x63,0xda,0x51,0x75,0x37,0xaa,0xe4,0xea,0x4e,0x3e,0x50,0x37,0xea,0x13,0xfd,0x8a,0xf7,0xf5, -0x8e,0x5b,0xab,0x7b,0xfe,0x49,0x67,0xf1,0x8d,0xc3,0x13,0xd4,0xa1,0x16,0x9a,0xd0,0xa5,0x30,0xa8,0x9d, -0xce,0xd6,0x68,0x2f,0x1c,0x76,0xc5,0xa1,0xc7,0x61,0x11,0xa7,0xcd,0x11,0xcc,0x68,0xbb,0xd8,0x36,0x80, -0x25,0x18,0xb6,0xe2,0x8e,0xdd,0x5d,0xe9,0xd0,0x26,0xdd,0x18,0x37,0x47,0x31,0x5b,0x28,0xdc,0xef,0x2f, -0x14,0xaa,0x6f,0x18,0x8f,0xac,0xab,0x6a,0x77,0x20,0x4d,0xb5,0x82,0x4f,0x55,0xe6,0xb1,0x51,0x73,0xf3, -0xe3,0x4d,0x58,0xe4,0x5d,0x49,0xd9,0x96,0xd4,0x08,0x51,0x83,0x69,0xbe,0xcd,0x5e,0x91,0xad,0x41,0xba, -0x54,0x13,0x4f,0x4c,0xa7,0x98,0x80,0x4c,0x76,0x4f,0xb1,0xf3,0x7e,0xeb,0x70,0x1f,0x0c,0xa9,0x24,0xbf, -0x6c,0x0e,0xb8,0x93,0xd2,0xf4,0xd0,0xc0,0x1b,0x7a,0x03,0xeb,0x55,0xd4,0xbc,0x0a,0x9b,0xf3,0x11,0x5d, -0xea,0x43,0x2c,0x53,0x29,0xd7,0x02,0xb7,0xc1,0x60,0x61,0xaf,0xdc,0x1d,0x0e,0x4e,0x2e,0x74,0x93,0xca, -0xa5,0x33,0x51,0x88,0xe0,0x3d,0xbd,0xc0,0x21,0xf5,0xae,0x1c,0x75,0x1b,0x07,0xa2,0x26,0xe0,0x29,0x7b, -0x32,0xc2,0xb2,0x56,0xeb,0xbb,0x73,0x7d,0x2e,0xce,0xe3,0xb7,0x8a,0x5a,0xf6,0xa8,0xfc,0x1d,0x29,0x90, -0xea,0xf3,0x5c,0x0c,0x7f,0x94,0x2e,0xb1,0xae,0xa1,0x30,0x9c,0xec,0x42,0xa5,0xb2,0x3e,0x81,0x6e,0x63, -0xb1,0x4e,0x2f,0x4f,0x88,0x91,0xb9,0x28,0xd7,0xd9,0xe5,0xf9,0x9a,0x39,0xcf,0xf5,0x22,0xcb,0x7f,0x5b, -0x83,0x32,0xae,0x89,0xeb,0x48,0x2e,0x03,0x7f,0xbb,0x8e,0xf1,0xae,0xe0,0xdc,0x04,0xc7,0x07,0xf7,0x0f, -0xce,0xb3,0x30,0x47,0x01,0xa2,0x5c,0x5c,0x1f,0xb1,0xda,0x76,0x7d,0x84,0xdc,0x0e,0xb2,0xb0,0xa4,0x57, -0x4a,0xe1,0x03,0xa0,0x9c,0x49,0x34,0xfd,0x39,0x9e,0xad,0x63,0xba,0xd6,0x7a,0xa0,0x21,0xf4,0x95,0x19, -0x14,0x2a,0xc4,0x02,0xa4,0xc7,0x07,0xfe,0xf0,0x6e,0x70,0x10,0x16,0x78,0x40,0xa9,0x8e,0x76,0xa1,0x5f, -0x99,0x3e,0x7c,0xf4,0xe0,0xed,0x83,0xe3,0xe9,0x7a,0x7f,0x3f,0x58,0xe3,0xc1,0xec,0x78,0x86,0xeb,0xfb, -0x94,0xe2,0x4e,0xcb,0xc2,0xaf,0xbe,0x5c,0xd0,0xf6,0xbc,0x1d,0x70,0xa8,0x41,0xcf,0xae,0x89,0x59,0x3e, -0xba,0x73,0x78,0xff,0xe8,0xe0,0xce,0xbd,0xfb,0x9e,0x80,0x83,0x74,0xa6,0x74,0x0b,0x92,0x14,0x84,0xcf, -0x56,0x3e,0x85,0xab,0xf8,0x76,0x95,0xba,0xb8,0xa8,0x75,0xd4,0x58,0x12,0xd5,0xd0,0x06,0xe1,0x3a,0x74, -0x1f,0x28,0x13,0x4d,0x01,0x2a,0x03,0x86,0x44,0x20,0xc2,0xa7,0x4b,0x9f,0xdd,0x4d,0x2e,0x7d,0x09,0x70, -0xcc,0xaa,0x1f,0x8d,0x99,0xa2,0x80,0x47,0x7e,0xf5,0x0b,0x44,0x85,0x4a,0x18,0xbd,0x86,0xa3,0x18,0xc2, -0x9c,0x2c,0x10,0x09,0x41,0xb1,0x5e,0xf3,0xb7,0x49,0x9c,0xe0,0xaa,0xda,0x9a,0xcb,0x23,0x3b,0x17,0x96, -0x3e,0x3e,0xa2,0x1e,0xa9,0xcc,0xb4,0xe6,0xaa,0x84,0x9e,0x0c,0x3b,0x44,0xbb,0xc6,0xef,0x78,0x6f,0xef, -0xda,0x4f,0x42,0x44,0xa7,0xb8,0x84,0x98,0x51,0xa7,0xe0,0x03,0x3a,0xac,0x51,0xf2,0x8e,0x95,0x99,0xf6, -0x91,0x56,0x62,0xc6,0x8e,0x18,0x90,0x1a,0x3c,0x1a,0x9b,0x8d,0x04,0x11,0xf5,0x60,0x38,0x32,0x2e,0x04, -0xf6,0xe5,0xa5,0xb2,0x85,0x07,0xe2,0x50,0x3e,0x7d,0xd5,0x30,0xa1,0xf2,0x4c,0x4b,0xde,0x1b,0xa3,0x66, -0xfd,0x04,0x26,0x82,0x93,0xf6,0x12,0x02,0x11,0x8b,0x5a,0x72,0x59,0xd4,0x4a,0x8b,0xfb,0x82,0xb1,0x53, -0x86,0x5a,0xad,0x9b,0x7c,0xfa,0x3a,0xb5,0x2c,0x9a,0x7d,0xe7,0x5e,0x2f,0xe9,0x1e,0x8a,0x3b,0x67,0x0c, -0xc7,0xbe,0x89,0xfa,0xbb,0x5e,0xcd,0xfd,0x9a,0x89,0x4e,0xba,0xa0,0x07,0x2f,0x5a,0x25,0xe9,0xd8,0x27, -0xa6,0x5d,0xd3,0x69,0xd6,0xbe,0x21,0x03,0xb1,0x48,0x50,0x86,0x0c,0x8c,0xa6,0x1d,0x74,0xe8,0xce,0xa1, -0x92,0x61,0xb5,0xe7,0x6f,0xeb,0xd9,0x57,0xed,0x47,0x30,0x92,0xe7,0x63,0x45,0x83,0x9f,0x1f,0xa7,0x8d, -0x8d,0x62,0xda,0x31,0xd2,0x02,0x24,0x0b,0x2b,0x9d,0x7b,0x4c,0x37,0x1e,0xb4,0x36,0x37,0xa7,0x79,0x4a, -0x8e,0xd6,0x2a,0xfd,0xb0,0xe7,0xd9,0x57,0xed,0x47,0x9a,0x31,0xfa,0x4d,0x77,0xec,0xb8,0x6e,0xc5,0xb4, -0x65,0x91,0x08,0x6d,0x55,0xff,0x3f,0xa8,0x18,0x51,0x9d,0xb4,0xac,0xbf,0xe6,0xd3,0x3e,0x28,0x96,0x83, -0x0b,0x82,0x6a,0x8a,0x20,0xe0,0x3f,0xad,0x25,0x97,0x6b,0x23,0xc0,0xb7,0x1e,0x74,0xca,0x65,0x23,0x1a, -0x8c,0xd6,0x59,0xed,0x4a,0x41,0xfe,0xa7,0x4a,0x73,0x10,0x0d,0x51,0x72,0x07,0xec,0xc0,0xa0,0x44,0xb1, -0x40,0x5e,0xf8,0x56,0x5f,0x4e,0x38,0x80,0x61,0x64,0x6d,0x41,0x1b,0x0a,0x91,0x0d,0xf1,0x35,0x8d,0xf2, -0x41,0xbf,0x00,0x42,0x17,0x3a,0x11,0xed,0x80,0x5c,0xe0,0x6c,0xee,0x3d,0x1b,0x87,0x65,0xa7,0xa5,0x18, -0x66,0xa0,0x07,0xd7,0xca,0xa5,0xa7,0x9e,0x80,0x49,0xe4,0x56,0xc0,0xf8,0xbf,0xdb,0x5b,0xe7,0x6a,0x9b, -0x71,0xed,0x78,0xb1,0xb7,0x7d,0xec,0xf2,0x96,0x99,0xa2,0xec,0x1a,0x59,0xd3,0x97,0x13,0x9d,0x77,0xc0, -0x06,0x5d,0xdb,0xee,0x4e,0x54,0x06,0xdd,0xc2,0xc6,0x4c,0xa3,0xd7,0x8f,0x84,0x1d,0xab,0x0c,0xe6,0x2f, -0xdd,0xfc,0x94,0x4e,0xfd,0xef,0x0d,0xb8,0x1c,0xab,0x35,0x61,0x77,0x13,0x74,0x02,0xc1,0xcd,0x00,0x94, -0x42,0x2d,0x75,0xb6,0x6c,0x68,0x4d,0xd9,0x19,0x99,0xdd,0x18,0x8e,0x4a,0x16,0x61,0xab,0x86,0xe4,0xd2, -0x10,0xb7,0x9e,0xdd,0x31,0xab,0x65,0xcc,0x6c,0xfb,0x12,0x64,0x1a,0x8f,0xac,0x48,0x9e,0x9b,0x5a,0x4d, -0x32,0x4d,0xe1,0x64,0x81,0xb3,0xcc,0x72,0x3b,0x29,0x52,0x9c,0x83,0x0b,0x47,0xa1,0x4f,0xce,0x53,0x63, -0xa4,0xb6,0x7d,0xae,0x37,0x66,0xb6,0xee,0x04,0x1f,0xdb,0xc0,0x20,0xb2,0xb6,0x8f,0x46,0x3d,0x2d,0xc3, -0x2a,0x53,0xb6,0x8d,0xaa,0x2e,0x2a,0x42,0xb8,0x42,0x72,0x04,0xa6,0x8c,0x03,0x36,0x25,0xcd,0x7a,0x5b, -0x44,0x9e,0x5c,0x79,0x9a,0x6c,0xe1,0x91,0xba,0xf4,0x42,0x7b,0x79,0x45,0x9e,0x50,0x0c,0xfd,0xf4,0x01, -0x2f,0x68,0x8f,0xd7,0xb5,0xa7,0x7b,0x00,0x10,0x4c,0x9e,0xd5,0x1b,0x7d,0xe7,0xa5,0x16,0x0c,0x90,0xb5, -0xcd,0x1b,0x3c,0x70,0xf1,0x12,0x2b,0x4c,0x3c,0x1c,0x00,0xc2,0xd0,0x52,0x4d,0x8e,0xe2,0x62,0x9c,0xd0, -0xb8,0xe7,0x71,0xc2,0x2e,0xc0,0x8d,0x21,0xae,0xac,0x0a,0x30,0x5e,0x50,0x4d,0x20,0x3e,0x0e,0x2d,0x65, -0xd8,0x22,0x25,0xa9,0x3a,0xf0,0x94,0x30,0x6f,0x01,0xae,0x97,0xb3,0x46,0x2d,0x58,0x9f,0xd2,0x30,0xc6, -0x09,0x98,0xcc,0x4b,0x1a,0xa6,0x2c,0x3f,0x08,0xab,0xba,0x65,0xc0,0xa9,0x8d,0x36,0x27,0xbb,0xcb,0xeb, -0x40,0x2c,0x37,0x07,0xda,0x70,0x73,0x55,0xc7,0x3d,0x63,0xea,0x32,0x7f,0xc6,0x1a,0x29,0x4b,0xaf,0x9c, -0xf0,0x24,0xc5,0x12,0xf2,0x4d,0x66,0xf7,0xd3,0x40,0x6a,0xfb,0xb0,0xb8,0x24,0x16,0x3c,0x9d,0xbf,0x01, -0xf3,0x0c,0x2b,0x54,0xc7,0x7a,0xcc,0xe0,0x26,0xd4,0x22,0x55,0xae,0x82,0x9b,0x4a,0x19,0x76,0x9e,0x56, -0x15,0x87,0xf8,0xf4,0x4e,0x8a,0xeb,0xfd,0x2a,0xfb,0x83,0x96,0x66,0x74,0x52,0x94,0xf3,0xb4,0xdc,0xa7, -0x27,0xe3,0xa5,0x02,0x7c,0x8e,0x34,0xde,0xf6,0x58,0x59,0x73,0x46,0x27,0xf0,0xcf,0x1e,0x4b,0xe3,0xa3, -0x64,0x55,0x17,0x63,0xf9,0x2c,0x3a,0x5c,0xd2,0x67,0x74,0xe2,0x46,0x4e,0xb8,0xae,0x8b,0x65,0x74,0xf8, -0x97,0x31,0xe3,0x33,0x47,0x5f,0x8c,0xfe,0xe2,0x85,0x95,0x6d,0xb8,0xe5,0x85,0x7f,0x77,0x0d,0xd7,0x12, -0x75,0xe8,0x10,0x5c,0x60,0xb7,0x61,0xc4,0x3d,0xe6,0xb1,0x77,0xf8,0x17,0x4f,0x4c,0x7e,0x8a,0x25,0x8d, -0xbd,0x77,0x6f,0x29,0xd2,0xf1,0xa1,0x54,0x06,0x76,0xaf,0x00,0x07,0xf9,0x5c,0x3f,0xe6,0x92,0x43,0xdd, -0x60,0x49,0xc4,0xd6,0xb2,0xb1,0xc7,0xd5,0xc9,0xac,0xb4,0xd6,0x5b,0xd4,0x4b,0x98,0x26,0x5d,0x2f,0xe2, -0xde,0x19,0xa8,0x62,0xe3,0x68,0xfa,0x7a,0xcc,0xe9,0xd8,0xd2,0x0e,0xa9,0xfb,0xdf,0x8c,0x55,0x5d,0x58, -0x63,0x29,0xb5,0x82,0xd9,0x3b,0x0c,0x05,0xa9,0x13,0x16,0xd9,0x32,0xf6,0x14,0x78,0x16,0xc6,0x00,0xfd, -0xe5,0xda,0xab,0xf5,0x7f,0xc2,0xb6,0x6e,0x6c,0xac,0xcd,0xe7,0x04,0xee,0x30,0x37,0x23,0x6a,0x61,0x7f, -0x79,0xc4,0x7b,0x77,0x66,0x03,0x8f,0xe5,0x48,0x0d,0xdb,0xdf,0x68,0x1c,0x05,0x67,0x9b,0x1e,0x61,0x40, -0x47,0xe3,0x05,0x75,0x73,0xb4,0xff,0x15,0xfd,0xb3,0xc6,0x7b,0xa4,0x26,0xc4,0x3e,0x0f,0xfa,0xd2,0x9a, -0x3f,0xc9,0x09,0x03,0x63,0x10,0x55,0x48,0x9c,0xd1,0xae,0x6c,0x7f,0x8f,0x79,0x1a,0xde,0x2c,0xb3,0xeb, -0x74,0xa1,0x71,0xc6,0x7b,0xf8,0x00,0x28,0x75,0x73,0xe2,0x4a,0x8a,0xeb,0x37,0x3c,0x5b,0x5f,0xa7,0x8b, -0x6c,0x0b,0xf6,0x10,0x7b,0x43,0x00,0x92,0x85,0x72,0x7c,0xd1,0x0c,0xec,0x96,0x94,0x19,0x87,0x68,0xe5, -0xbc,0x5e,0x98,0x89,0xb4,0x25,0x6d,0xb1,0x01,0x42,0xaf,0x32,0x10,0x5c,0xb0,0x31,0x1f,0xec,0x9e,0xd7, -0xac,0xfc,0xa2,0x05,0xbf,0x7f,0x3a,0x4d,0x89,0xb4,0x0c,0x07,0x74,0x12,0x3d,0xc5,0xeb,0xfd,0xfd,0x83, -0xf0,0xac,0x8e,0x6f,0x4c,0x7f,0x78,0x4d,0x87,0xbc,0xcb,0xaa,0xec,0x24,0x5b,0x64,0xc4,0x7c,0x78,0x17, -0xd9,0x7c,0x9e,0xe6,0x5e,0xa8,0x57,0x99,0xc7,0xcb,0x8c,0xa8,0xe3,0x92,0x3e,0x5e,0xa4,0x35,0xd1,0xd0, -0x37,0xcb,0xe4,0x14,0x7d,0xed,0x8d,0xbc,0xf0,0x8c,0x46,0xf7,0x07,0x19,0x17,0xef,0xf3,0xd1,0x88,0xd2, -0xcd,0xeb,0x78,0xea,0xfd,0x90,0x9e,0xfc,0x96,0xc1,0x18,0xfc,0x45,0xf1,0x07,0xfd,0xbd,0xac,0xbc,0x19, -0xed,0xfd,0xdb,0xa6,0xa3,0x8c,0xbd,0x7d,0x06,0xa6,0x69,0x20,0x0e,0x1e,0x37,0x05,0x0a,0xa3,0x8a,0xdd, -0x74,0x9d,0x34,0xf9,0x60,0xa8,0x28,0xd7,0x73,0x9c,0xd3,0x54,0x5a,0xc3,0xdb,0x78,0x12,0xcc,0xd1,0x3b, -0xf4,0xa2,0x9c,0x95,0x3b,0x94,0xed,0xb7,0xab,0xcb,0x13,0xc4,0x0e,0x4d,0xf2,0xec,0x92,0xe5,0xb5,0xcf, -0xa8,0x45,0x7c,0xc1,0xea,0x71,0xd1,0x29,0x2e,0x56,0x97,0xcd,0x2d,0xed,0xea,0x8b,0x97,0xaa,0x16,0xb8, -0x5d,0xa4,0xd7,0xdf,0x94,0xc5,0x95,0xbe,0x7e,0x73,0x41,0xdc,0xc4,0x6f,0x7c,0xd7,0xf4,0x05,0xdd,0x11, -0x57,0x97,0x3e,0x35,0x77,0x45,0x93,0x81,0x4c,0x6c,0xbe,0x58,0xd2,0x81,0x4c,0x24,0x9b,0xd9,0xbc,0xb8, -0xe2,0xab,0x3f,0x38,0x26,0x11,0x5f,0x15,0xc5,0x25,0x6b,0x19,0xa9,0xd6,0x10,0x1e,0x52,0x67,0x78,0x67, -0x8b,0x22,0xa9,0xbd,0xc8,0xa3,0x47,0x4f,0xf8,0x12,0x82,0xf1,0xf7,0x8b,0x3e,0x29,0x96,0xc8,0xa3,0x3e, -0x6b,0x9d,0xd1,0xff,0xd6,0xba,0x57,0x46,0xea,0x4e,0xf8,0x88,0x8e,0xe7,0xe6,0x2a,0x3e,0x55,0xec,0x51, -0x1d,0xb0,0xfd,0x80,0x8c,0x97,0x9a,0x8e,0x2b,0xf6,0x1b,0x7e,0x09,0x97,0x84,0x30,0x51,0x56,0xf7,0x3c, -0x78,0xb4,0xaf,0x89,0xd4,0x4f,0xdf,0x57,0xb3,0xd0,0x72,0x62,0x4d,0xf6,0xf6,0x3c,0x1a,0x54,0x8f,0xce, -0xb3,0x89,0x25,0x64,0x85,0xd9,0x89,0x72,0xd5,0x81,0x17,0x7f,0x00,0x98,0x92,0x05,0x5c,0x46,0xe9,0xe8, -0xaf,0x18,0xb6,0xdc,0x82,0x13,0x86,0xbb,0x1f,0x7d,0x72,0x47,0xb1,0x6b,0x1c,0x5e,0x3d,0x63,0x20,0x60, -0x80,0x95,0x71,0x77,0x00,0x79,0x26,0xf6,0x72,0x1e,0x78,0x4f,0x69,0x7b,0x84,0xa5,0xc5,0x66,0xa6,0x82, -0x77,0xea,0xf7,0x2a,0xc7,0x7c,0xc0,0x90,0x45,0x1c,0x93,0xd7,0x97,0x36,0xc8,0xcc,0xa1,0x46,0x4c,0x3c, -0x84,0xbe,0xbc,0x86,0x3c,0xa0,0x4b,0xf0,0x60,0xc6,0x06,0xaf,0x98,0xf5,0x9a,0x25,0xc6,0x8d,0xe3,0x5f, -0x43,0xf0,0x60,0x38,0xe4,0xa3,0x49,0x31,0xb5,0xfd,0x22,0x2d,0x33,0x16,0x3e,0xc0,0xe9,0xb7,0xd5,0x1b, -0x31,0x4b,0x0a,0x12,0xe5,0xda,0x8b,0x51,0x65,0x8b,0xd6,0x09,0x02,0x77,0xd4,0x8d,0x62,0x1c,0x7e,0xe4, -0x9c,0x5d,0xce,0x08,0xa0,0x3c,0x61,0x7a,0x26,0xc4,0xc7,0x8e,0xf0,0x9f,0x1a,0x57,0x77,0x30,0xed,0x31, -0x1c,0xc1,0x17,0xbe,0x19,0x77,0x11,0x08,0x3f,0xe7,0x6a,0x21,0xd4,0x89,0x97,0x17,0xe5,0x65,0xb2,0x50, -0x7e,0x64,0xec,0x21,0xbc,0xac,0x39,0xcd,0xb2,0xc6,0x19,0x47,0x22,0x14,0x50,0x77,0xe6,0x13,0x9a,0x00, -0x0c,0xb3,0xcc,0x33,0x9f,0x6d,0x40,0x19,0xc3,0x61,0xbd,0xce,0xaa,0x27,0x40,0xa6,0x06,0x4a,0xca,0xa4, -0xa0,0x8e,0x8f,0x04,0x37,0xa6,0x61,0x22,0xa7,0x9e,0xec,0x1d,0x44,0x8a,0x24,0x4a,0xc3,0xac,0xcb,0xec, -0x59,0xad,0x8b,0xdb,0xc4,0x46,0x2f,0x28,0xed,0xbf,0xb8,0xbb,0x50,0xbd,0xd5,0xe3,0x63,0x12,0xc0,0x6a, -0x14,0x7c,0x03,0x2b,0x4a,0x5e,0xa7,0xa7,0x75,0x65,0x60,0x5f,0x55,0x5c,0xdd,0xaf,0x31,0x0b,0x68,0xfa, -0x36,0x49,0x28,0x05,0x57,0x6c,0xf2,0x42,0x75,0x4c,0xf4,0x07,0x4e,0x89,0x67,0x16,0x76,0xa0,0x21,0xff, -0x3a,0x09,0xce,0x53,0x55,0x4f,0x3d,0x75,0xb4,0xc9,0x72,0x6f,0x6f,0x55,0x8b,0xa0,0x8c,0x2e,0x5f,0xcb, -0x57,0xa1,0xd7,0xf0,0x56,0xae,0x93,0x8c,0xd9,0xcf,0x3c,0xac,0x3b,0x00,0xcc,0x34,0x82,0xb2,0xee,0x12, -0xc3,0xfc,0xe7,0xc5,0x2a,0x51,0xab,0xb1,0x1a,0x58,0xcd,0x2e,0x2e,0x2f,0x98,0x8b,0x61,0xde,0x64,0x8e, -0x20,0xce,0xaf,0xb8,0x7e,0x89,0x91,0x20,0xe9,0xfe,0xb6,0x98,0xa6,0xf8,0x29,0xc4,0x8c,0xdd,0x3d,0x30, -0xec,0xa1,0xfb,0x52,0x35,0xdf,0x9a,0x10,0xbc,0x05,0x34,0x99,0x35,0x23,0xd1,0xdb,0xdd,0xe0,0x1e,0xf6, -0xb9,0x93,0x6f,0x9a,0x6f,0xa2,0xd1,0xa6,0xa7,0xc3,0x6f,0xcf,0x84,0xf6,0xe1,0x01,0xda,0x6f,0x9f,0x59, -0x14,0x53,0x4a,0x1c,0x91,0xe6,0x4b,0xe8,0x52,0x71,0x34,0xde,0x0f,0x3c,0x03,0x7b,0x8e,0x1b,0x66,0x06, -0xa6,0x03,0xcc,0x41,0x11,0xbd,0x35,0xc3,0xeb,0x44,0x66,0x80,0xc0,0xf3,0x06,0xc8,0x48,0x9d,0xd3,0x6c, -0x0e,0xe0,0x40,0xb1,0xa2,0xdd,0xf1,0x82,0x88,0x8e,0x9c,0xe3,0xf2,0xe8,0x73,0x16,0x88,0x66,0x94,0xf3, -0xd7,0x08,0xcf,0x89,0xfc,0x21,0x1b,0x5d,0xaf,0xe9,0xef,0xfe,0x3d,0xfe,0x1d,0x59,0x1e,0x4a,0x9b,0x30, -0x31,0xe7,0x61,0x43,0xff,0x9a,0xba,0x81,0xfc,0xc4,0xaf,0x82,0x8e,0x24,0xb0,0x4d,0x77,0x6e,0x39,0xde, -0xb7,0x04,0xd3,0x68,0x0b,0xce,0x4d,0x34,0xb4,0x6d,0x80,0x01,0x69,0x75,0x19,0xcb,0x5c,0xce,0x1a,0xe3, -0xe2,0xe4,0x28,0xe3,0x23,0x16,0x00,0x94,0x92,0xd9,0xcc,0x9a,0x6d,0xf0,0xa6,0xe3,0xbd,0xc3,0x80,0xf7, -0x6c,0x1c,0x59,0x21,0x23,0x23,0x9c,0xab,0xc9,0xaa,0xea,0x12,0x59,0x93,0x75,0xc3,0x4a,0x9f,0xae,0xb3, -0xb1,0x3e,0x98,0xbe,0xbd,0x4a,0xd3,0x3c,0x7e,0x16,0x3e,0xdb,0x66,0x02,0xf0,0x2c,0x04,0x3d,0xea,0x31, -0xc2,0x46,0xc0,0x50,0x39,0xb4,0x13,0x03,0xa4,0x6d,0x38,0x28,0x93,0x25,0xad,0x17,0xa5,0x1e,0xa9,0x68, -0x34,0x01,0x93,0xca,0x93,0x09,0x37,0x43,0x6d,0x36,0x23,0x29,0xc4,0xd9,0xa7,0x8a,0x6b,0xad,0x7d,0x4e, -0xca,0x5a,0x0b,0xd9,0xae,0x62,0x6d,0x5a,0xa1,0x95,0xd3,0x34,0x2e,0x71,0x29,0x97,0x2b,0x80,0xf7,0x17, -0xed,0xed,0x2c,0x6f,0xb6,0x33,0xda,0x38,0x56,0x65,0x57,0x2a,0xc0,0xad,0x5c,0x2a,0xda,0xa8,0xeb,0x6b, -0x26,0x8b,0x8e,0x15,0x3e,0x69,0x0c,0x64,0x83,0xc8,0xfa,0xc4,0xd4,0xbe,0x79,0x4d,0x6c,0xee,0xaa,0x07, -0xb7,0x8a,0x08,0xc6,0xed,0x45,0xd9,0xcd,0x1f,0xce,0x57,0xc2,0xb5,0x29,0x0c,0xeb,0x82,0x3a,0x24,0x36, -0x5d,0x36,0xb5,0xfa,0x72,0xa6,0xa5,0x6d,0xed,0x2f,0xef,0x22,0xfe,0xec,0x61,0xff,0x3b,0x25,0x3c,0x96, -0x6c,0xb5,0xb4,0x8e,0xba,0xd7,0xd7,0x9d,0xba,0xdf,0x74,0x7e,0x70,0xb7,0x1e,0x34,0x77,0x6e,0x7e,0x55, -0x9d,0x2e,0x95,0x98,0xc6,0x7e,0xd4,0x18,0x76,0x8a,0x65,0xa9,0xce,0x5f,0xa3,0xc8,0x73,0x08,0x50,0xea, -0xd3,0xdc,0x78,0xc2,0x6f,0xe9,0x53,0xf3,0x5a,0xa0,0x90,0x36,0xf6,0x94,0xe4,0x68,0x0d,0xd6,0x0c,0xb5, -0x5e,0x85,0x56,0x66,0xf1,0x8d,0x31,0xcb,0x6a,0x6d,0x7b,0x6e,0xb0,0xc6,0x1d,0xd1,0xee,0xa0,0xbe,0x96, -0x84,0x57,0xeb,0xd2,0xf1,0x78,0x9a,0xca,0x78,0x51,0xed,0x95,0x02,0x9e,0x13,0xcb,0x96,0xa0,0xde,0x4d, -0xdc,0xa4,0x1a,0x27,0x04,0x0b,0x4f,0xba,0x42,0x5e,0x70,0x6c,0x22,0xe0,0xa0,0xe0,0x5c,0xcf,0x67,0xed, -0x09,0x11,0xe7,0xce,0x86,0x27,0x52,0x9a,0x6b,0xee,0x53,0x53,0x42,0xf7,0x11,0x10,0x5b,0xb6,0xd6,0xbe, -0x55,0x4f,0xa9,0x0d,0xf3,0xdb,0xfa,0xf3,0x99,0x80,0x7b,0x34,0x24,0xb0,0xb7,0x29,0xcc,0x56,0x5f,0x45, -0x0d,0x59,0x71,0xda,0xc3,0x2f,0x07,0x8c,0xf4,0xcb,0x86,0x66,0xf6,0x08,0x0c,0x2b,0x06,0x70,0x7a,0x4b, -0x54,0xa0,0xfb,0x94,0xf7,0xc5,0x9b,0x76,0xb3,0x5b,0x2d,0xc1,0x1a,0xe4,0x07,0xb6,0x04,0xda,0xef,0xab, -0x9f,0x31,0x4e,0x61,0x32,0x73,0x83,0x43,0x4a,0xd2,0xaf,0x64,0xa4,0xbe,0xbe,0xc2,0xce,0xd5,0x7d,0x37, -0xfc,0x62,0xff,0x45,0x52,0x5f,0x0c,0x4f,0x0b,0x1a,0xb5,0xbb,0x7c,0xf9,0xea,0x59,0x70,0x70,0xcf,0x32, -0xf0,0xf3,0xf8,0x5b,0x4f,0x42,0xc8,0x5c,0xc7,0xed,0x59,0x19,0x36,0x63,0x04,0x4f,0x58,0x4c,0xb3,0xf3, -0x3a,0x7c,0x57,0x87,0xef,0x6b,0x71,0x65,0x13,0x57,0xd6,0x35,0x7c,0x4c,0xd7,0x70,0x2c,0x05,0x20,0xca, -0x25,0xbd,0x6b,0x1c,0xa4,0x05,0x43,0xed,0x81,0x3e,0xc5,0x59,0x7e,0x48,0xdf,0x85,0x37,0x35,0x08,0x34, -0xac,0x6b,0x6f,0xbc,0xbb,0x5e,0x34,0xed,0x45,0x09,0x60,0x42,0xc9,0x87,0x51,0x26,0xe7,0xfc,0xce,0x80, -0x0c,0xfa,0xb9,0x1a,0xbd,0x50,0x73,0x3d,0x30,0x37,0xc0,0xb9,0x7f,0xb6,0x09,0x55,0xee,0x51,0x67,0x03, -0x77,0x83,0x5c,0x28,0xdf,0xef,0x29,0x55,0x61,0x16,0x44,0xb0,0xd2,0x33,0x9e,0x32,0x63,0x5b,0x8e,0x38, -0x62,0x5b,0x8a,0x96,0xee,0x12,0x0a,0xc2,0x72,0x16,0x7e,0x37,0xd4,0x4d,0x21,0x42,0x1d,0x3b,0x77,0xec, -0x6f,0xe0,0x3c,0x31,0x18,0x0b,0xb5,0xe8,0x76,0x54,0x24,0xcb,0x68,0xfa,0xc7,0xac,0xb9,0x6d,0x63,0x46, -0x4c,0xbe,0x1b,0x36,0x49,0x4d,0x0e,0xb4,0x60,0x9c,0xe7,0x3a,0x62,0x93,0xec,0x7f,0xd5,0x32,0x4d,0xe7, -0x5b,0xe2,0x1a,0x01,0x20,0xa0,0x0b,0x42,0x62,0x1d,0xed,0x21,0xe0,0x8d,0x6e,0x34,0xfe,0x59,0x44,0x9c, -0x3d,0x62,0x87,0xd5,0x6d,0xe0,0x3e,0x46,0xb3,0x0b,0x35,0x3d,0x8e,0xa8,0x27,0x79,0xca,0x46,0x92,0xd6, -0xe0,0xed,0x58,0x56,0xcc,0xf4,0xc2,0x46,0x89,0xa4,0xf9,0x55,0x9c,0x9d,0x4d,0x4a,0x43,0xd3,0xe3,0x51, -0xa4,0x0f,0x79,0xc6,0x64,0xa1,0x79,0x0b,0x1f,0x7b,0x73,0x83,0x53,0x88,0x9a,0xa2,0x68,0x6a,0x65,0xe7, -0x62,0x3f,0x9f,0x36,0xcf,0x67,0xd1,0x96,0x34,0x86,0x58,0x07,0xa1,0x10,0xcb,0x52,0xd0,0x0a,0x10,0x5e, -0x8c,0x2f,0x76,0xe5,0x10,0xe3,0xab,0x5b,0xc6,0x7b,0x08,0xc2,0x72,0x58,0x2c,0x68,0xeb,0x1e,0xea,0x8e, -0x0a,0x9b,0xcb,0x16,0x36,0x87,0x0d,0x7f,0x86,0x8f,0x38,0x70,0x59,0xb1,0x98,0x37,0x9b,0x0c,0x72,0x53, -0x65,0xb6,0x11,0x16,0xd4,0x0b,0xec,0xc9,0x9d,0x78,0x4f,0x09,0x11,0x97,0x62,0xbb,0x7d,0x8c,0x58,0x30, -0x8b,0xca,0xe3,0x97,0x34,0x60,0x22,0x6e,0x44,0x30,0xe1,0x48,0x7b,0x88,0x63,0xb7,0x84,0x76,0x82,0x57, -0x6a,0xea,0x1b,0x81,0x4e,0xbd,0x09,0x53,0x65,0x86,0xa3,0xde,0x6d,0x3b,0xb3,0xc6,0x1d,0x47,0xa0,0x54, -0xe1,0x96,0x70,0x0f,0x0b,0x12,0x6f,0x0b,0xb3,0x44,0x04,0xb8,0xdf,0x99,0xf8,0x3c,0xf6,0xec,0xc3,0xc9, -0x06,0xc8,0xb2,0x8e,0x4f,0xcf,0x19,0xd1,0xa5,0xea,0xc2,0xc3,0xd9,0xa6,0x66,0x93,0x3e,0x08,0x3a,0xcd, -0x7c,0x02,0x2a,0x27,0xde,0xc7,0x49,0x98,0xc1,0x41,0x44,0x46,0x8a,0x2d,0x63,0x1b,0xab,0x96,0x44,0x71, -0x0d,0xd2,0xbd,0x2a,0x11,0x4e,0x3c,0x6c,0xbc,0xd8,0x6f,0x95,0x11,0x77,0xb6,0xdb,0x58,0x2c,0x0e,0xc7, -0x1a,0xa6,0x4a,0xa0,0x51,0x10,0x86,0x4a,0xd7,0xa6,0x17,0x68,0x42,0x0c,0x6f,0x6c,0xb0,0x89,0x5a,0xc2, -0xa2,0xc1,0xfe,0xc6,0xaa,0x96,0x85,0x91,0xd1,0x6f,0x90,0x23,0x95,0x40,0xa0,0x5d,0x4b,0xef,0xe7,0x40, -0x53,0x48,0xdf,0xc3,0x90,0xb6,0x04,0x5e,0x86,0xd5,0x8d,0x6c,0xac,0x91,0x05,0xe2,0x3b,0x81,0xbf,0x5c, -0x79,0xe0,0xd3,0x27,0x6c,0x4f,0x64,0x5c,0xc0,0xd8,0xe4,0x28,0xe9,0x26,0xbc,0x34,0x0e,0x9e,0xcd,0x47, -0xff,0x4b,0x22,0x07,0xd8,0x81,0x38,0x11,0x0a,0x80,0xbe,0x01,0x89,0x56,0xfa,0x79,0xc3,0x89,0xec,0xed, -0xf1,0x2b,0xbd,0xb2,0xa0,0xaf,0xe7,0x07,0x98,0x63,0x32,0xae,0xb9,0x82,0xfe,0x77,0x62,0x69,0x06,0x63, -0xa0,0xe5,0xe7,0x4c,0x85,0x7a,0x20,0x48,0x64,0xf4,0x7b,0xf7,0x49,0xd5,0xc5,0xbe,0xc1,0xf6,0xb8,0xad, -0x5f,0xc3,0xdc,0xe9,0x2e,0x80,0xf2,0x4c,0x75,0xe7,0x7a,0xd0,0x27,0x35,0xb7,0xd2,0xd7,0xb3,0x56,0x67, -0x97,0x13,0x1d,0xf2,0x33,0x12,0xd8,0xc4,0x5c,0xcf,0x4c,0xc1,0x42,0x74,0xd0,0x5c,0xa6,0x12,0xce,0x29, -0x53,0x9d,0x2b,0xbf,0x96,0x53,0x11,0x94,0x50,0x75,0xd3,0xb1,0xb5,0x74,0x6c,0x2d,0x1d,0xab,0x54,0xf7, -0xe8,0xcf,0x7a,0x66,0x26,0x3c,0xa6,0x1a,0x3f,0x68,0xfa,0x73,0x97,0x43,0xc1,0xaa,0xbe,0xac,0xb9,0x2f, -0x9b,0xc0,0x6d,0x09,0xeb,0xa8,0x4b,0xfa,0x82,0x06,0x14,0xdf,0x49,0x6d,0x9d,0x1b,0x8b,0x50,0xe9,0x59, -0xaf,0x5b,0xb5,0x09,0x5c,0x31,0x8e,0xf0,0x05,0x5e,0xe8,0x81,0xb6,0xd0,0x0f,0x78,0x83,0x8e,0x30,0xc7, -0x40,0xdb,0x9c,0xe5,0x70,0x9e,0xd3,0x17,0xf6,0x86,0x65,0x03,0x77,0x2b,0x26,0x10,0x91,0xcb,0xbb,0x30, -0x19,0x79,0xbf,0x11,0xa2,0x0a,0xb2,0xa5,0x68,0xda,0xd7,0x50,0xd8,0x02,0xde,0x25,0x14,0x28,0x5b,0x4b, -0x12,0x50,0x2d,0xa8,0x86,0x8f,0x8a,0xab,0x3c,0xfa,0xda,0x97,0x4a,0x07,0x21,0x3f,0xfb,0x6e,0x89,0x27, -0x5c,0x7f,0xf5,0xe4,0xad,0xc0,0x77,0xd0,0x53,0xd5,0xca,0x20,0x04,0x09,0x7e,0x96,0x37,0x42,0x70,0xc9, -0x61,0xc3,0xcf,0x5f,0xae,0x6a,0xeb,0x05,0x67,0x24,0x2f,0x54,0x3e,0xcd,0x3b,0x95,0xdd,0x47,0x04,0x3a, -0x49,0xbb,0x04,0x5e,0xb7,0xb1,0xd6,0xd4,0x5a,0x5a,0x27,0x13,0x12,0x3a,0x50,0xd9,0xeb,0xea,0xec,0xf4, -0xb7,0x2e,0xbc,0x39,0xfc,0xac,0xf3,0x66,0xfe,0xf2,0xbc,0x38,0x67,0x8e,0x9f,0x0d,0xef,0x69,0x7e,0xe4, -0xb6,0xe3,0x63,0x1a,0x63,0x9c,0x42,0x86,0xf1,0xc5,0x95,0xac,0xdf,0xdc,0xcc,0xad,0xfd,0x7d,0x9a,0x5d, -0x63,0xfd,0x09,0xaf,0x55,0xe6,0x22,0x69,0x12,0x22,0x56,0xb9,0x36,0x64,0x32,0x55,0xba,0x4c,0x5d,0xfa, -0x6a,0x2a,0xa2,0xf9,0x19,0xc3,0x87,0x26,0x25,0xdb,0xb7,0xcb,0x2d,0x9b,0xd0,0xbe,0x4b,0x16,0xf1,0xe1, -0x67,0x76,0x02,0xa7,0x79,0xb0,0x75,0x7c,0xc7,0x64,0xf2,0x07,0x3f,0x30,0x5f,0xa2,0x2a,0x6e,0x32,0xd1, -0xd7,0x85,0x36,0x43,0x40,0xdc,0xfc,0x82,0x0e,0x0a,0x5f,0x8e,0x46,0x34,0x5c,0x55,0x1d,0xdd,0xa3,0x0b, -0xc3,0x38,0x7f,0x3e,0x1a,0xe9,0x7d,0x98,0x96,0x42,0xf2,0xbe,0x05,0x07,0x6c,0xd0,0xc6,0x38,0xc3,0x89, -0xc3,0x8b,0x40,0x2a,0x5b,0x47,0x20,0x31,0xb9,0xa2,0xf1,0x16,0xd9,0xef,0x87,0xf3,0x77,0x20,0x63,0x73, -0x66,0x80,0x3b,0x6d,0x50,0x12,0x6e,0x9d,0x2a,0x53,0xde,0x54,0x5b,0x91,0x41,0xda,0x90,0x1e,0x61,0x9f, -0xda,0x47,0xcc,0x54,0x3d,0x81,0x7d,0xbc,0x1d,0x34,0x44,0xce,0xcd,0xb4,0x31,0x8f,0x95,0xe1,0x6f,0xe3, -0x91,0x64,0xe0,0x3b,0x5e,0x22,0x16,0x07,0x1f,0xf0,0xd8,0xe7,0x0b,0xcf,0xe9,0x33,0xc1,0x8c,0x48,0xe1, -0x60,0x5f,0xa9,0xcb,0xf0,0xb6,0x8a,0xaa,0xaf,0x63,0xaf,0xf6,0xb4,0x91,0xb1,0x02,0x1e,0x41,0x86,0x7c, -0xf5,0xbd,0x4e,0x10,0x9b,0xc2,0xb4,0x12,0xee,0xba,0x0e,0x4f,0x6a,0x13,0x6a,0x14,0xf8,0x83,0x4f,0xd9, -0xda,0xae,0x85,0xf3,0x83,0x17,0xb7,0x0b,0xc9,0x28,0x3d,0x12,0x6d,0x95,0x41,0x29,0x43,0xba,0x07,0x6e, -0x46,0x1f,0x04,0xd6,0x6a,0xbe,0xda,0x0a,0x76,0xd7,0xa9,0x9b,0x2b,0xa3,0xb3,0xe2,0xbd,0xd2,0x36,0x0f, -0xcd,0x52,0x21,0x0a,0x25,0xfa,0xb9,0x87,0x9f,0xa0,0x83,0x9b,0xd1,0x50,0x52,0x27,0xc4,0x2e,0x26,0x2e, -0x0e,0xa5,0x5a,0xf6,0xc6,0xf6,0x64,0x85,0x8a,0x03,0x61,0x0c,0x46,0x11,0xe0,0x3e,0x56,0xbd,0xa1,0x64, -0x42,0x2d,0xf3,0x1b,0x11,0x66,0x59,0x50,0x11,0xa0,0xe0,0x5a,0x8f,0x31,0xb9,0xae,0x15,0xd2,0x46,0xe0, -0x42,0xa2,0x32,0xbd,0xa7,0x0b,0x7e,0xe6,0xf6,0x0c,0xe3,0xa9,0x66,0x8d,0x2a,0x26,0xb3,0x15,0x53,0x1c, -0xa2,0x5e,0xa9,0x62,0xea,0x00,0xf8,0xf6,0x7e,0xea,0x62,0xcd,0x50,0x63,0x06,0x90,0x5c,0xe4,0x92,0xc9, -0xb9,0xc9,0x44,0x98,0x13,0xc9,0x42,0x23,0x02,0x72,0x06,0x65,0xac,0x3c,0x51,0x25,0x62,0xa3,0x20,0x05, -0x72,0x05,0x4b,0x0d,0x1b,0x5f,0x72,0x54,0x37,0xdd,0x07,0x91,0xc0,0x6c,0xdc,0xb4,0xa1,0x73,0x25,0x0a, -0xb3,0x33,0x4f,0xa9,0x06,0x32,0x7d,0x05,0x83,0x4f,0xa2,0x68,0x29,0x17,0x3d,0xb5,0x49,0xaa,0x39,0x6c, -0x84,0x79,0xbd,0xe8,0x3b,0x0a,0xbc,0x50,0x2f,0x0f,0xf0,0x4f,0xac,0x4d,0xed,0x9d,0x87,0x9d,0x60,0x84, -0xe0,0xa7,0x9b,0x83,0xaf,0x04,0x05,0x6e,0x85,0x0a,0x16,0x4b,0xa9,0x38,0x9b,0xd2,0xc9,0x77,0x36,0x0e, -0xec,0x11,0x91,0x8a,0xe4,0x3c,0x53,0xaf,0x3b,0x82,0x90,0xd0,0x25,0x8a,0xcc,0x8f,0xb7,0x07,0x94,0xc6, -0xa2,0xd5,0xac,0x5c,0x4e,0xf2,0x8d,0x97,0x4e,0xcf,0x1c,0x12,0x4c,0x34,0x55,0xf1,0x83,0xe3,0xab,0xc1, -0xc1,0x79,0xd0,0xcb,0x66,0x9c,0xd4,0x5a,0x1d,0x66,0x46,0x71,0xcc,0xcf,0xdc,0xf3,0xb1,0x83,0x32,0xd6, -0x9a,0xc6,0x26,0xf4,0x2c,0x87,0x15,0x3a,0x61,0xf1,0x35,0xff,0x8d,0x33,0xc3,0x84,0xeb,0x5c,0x26,0x09, -0xc7,0xce,0x53,0xef,0x0b,0x18,0x0d,0x28,0x53,0xa0,0x2b,0x25,0x3a,0x11,0x53,0x78,0x21,0x78,0x6b,0x8d, -0x43,0xb4,0x16,0x07,0x19,0x46,0xdf,0x7a,0xab,0x12,0x26,0x6b,0xbc,0xc1,0xa3,0x16,0x89,0x5a,0x76,0xfd, -0x8f,0xbb,0x24,0x4a,0xa4,0x5a,0xb7,0x93,0xa8,0x96,0x23,0xf3,0xed,0x24,0x4a,0x71,0x7e,0xda,0x0d,0x0f, -0xf9,0x3f,0xc9,0xae,0x39,0xfe,0x59,0x3a,0xeb,0x90,0xaa,0x4e,0x1d,0xff,0x1c,0xa9,0xda,0xd9,0x46,0x78, -0x98,0x92,0xeb,0x3a,0xf0,0xce,0x2a,0x46,0xdd,0x96,0x7c,0x7a,0xe6,0x50,0x95,0x8f,0x27,0x1a,0xa2,0x1e, -0xfb,0x48,0x02,0x81,0xc4,0x8c,0x65,0xb8,0xd4,0xab,0x3f,0x39,0x11,0x0b,0x81,0x7e,0x61,0x6d,0x9b,0x9c, -0x78,0x94,0x9e,0x55,0xd0,0x96,0xc1,0xe7,0x84,0x95,0x66,0xcf,0x68,0xeb,0x23,0x6e,0x7d,0x14,0x44,0x57, -0x5a,0xd7,0x63,0xa2,0xb6,0x53,0x0f,0xbc,0xed,0x3e,0x64,0x5f,0x96,0x32,0x3d,0x9b,0x8c,0x10,0xbe,0x72, -0x23,0xd5,0xa2,0xfe,0x81,0x5d,0x42,0x51,0x7a,0xc4,0x84,0xd6,0x97,0x8b,0x27,0x74,0x15,0x7a,0xa7,0x8b, -0xa4,0xaa,0x60,0xa7,0x80,0x5f,0x7c,0xec,0x61,0xfc,0xdc,0x6d,0x59,0x88,0xb7,0x25,0xef,0xd4,0xdb,0xf5, -0x96,0x96,0x6d,0x09,0x2e,0x59,0xbb,0x66,0xb7,0xb6,0xcd,0xad,0xce,0x91,0x3b,0x2c,0x14,0x4e,0xac,0x2d, -0x49,0xed,0xc9,0x1b,0xea,0xe7,0xba,0xf5,0xf1,0xc7,0x96,0xd2,0x3e,0xaf,0xa8,0xd1,0x02,0x84,0x59,0x9a, -0xcc,0x5f,0xe6,0x0b,0xc4,0xc8,0xba,0x4c,0xae,0x9f,0xf3,0x5a,0x41,0x4f,0xa5,0x8b,0x85,0x32,0xa8,0x51, -0x77,0xaf,0x44,0x65,0x88,0x4f,0x8a,0x2b,0x7a,0x95,0xe3,0x79,0xb1,0x50,0x57,0xab,0x2a,0x7d,0x91,0x00, -0x6e,0x91,0xc3,0x21,0x7e,0xcd,0x3a,0x45,0x4e,0xc0,0x56,0x56,0x8f,0xe7,0xe2,0xfe,0x6e,0x9f,0x89,0x78, -0xf7,0x37,0x53,0x99,0x6d,0xd7,0x9d,0x4d,0x94,0x8f,0x79,0x1d,0x5d,0x1e,0x55,0xe2,0x21,0x06,0xef,0x76, -0x20,0x95,0x70,0x25,0x4a,0xbb,0xb6,0xec,0x2e,0xd8,0xbe,0xd2,0xf9,0xe0,0xa1,0x30,0x03,0x75,0x21,0xbe, -0x1d,0x65,0xb5,0x0e,0xbf,0x51,0x66,0xa2,0xc4,0xa1,0x6c,0x33,0xd8,0x95,0x4d,0xa3,0xb6,0x85,0xaa,0x10, -0x88,0x8e,0x55,0xb8,0xda,0x15,0x6f,0x24,0xd8,0x6c,0xe2,0x6f,0x70,0xe0,0x2f,0xe3,0x76,0x08,0x5a,0x6f, -0xc7,0x1b,0x7c,0x4f,0xdc,0x2c,0x80,0x24,0x34,0x2c,0xca,0x68,0x5c,0xc4,0x44,0x57,0xf9,0x5b,0x0b,0xb2, -0x99,0x52,0x16,0x9c,0x8c,0x0d,0x5a,0xcb,0x41,0x2c,0x77,0xe3,0x2a,0xfe,0xde,0x07,0x58,0x19,0xad,0xdb, -0x4a,0x69,0x6c,0x6c,0x68,0x3a,0x5e,0x02,0x61,0x15,0xd8,0xe1,0x6b,0x35,0x65,0xfc,0x9f,0xef,0x5a,0xab, -0x9c,0xdb,0x7b,0x77,0xb7,0x63,0x25,0xec,0x1c,0xff,0x40,0x46,0x74,0x5b,0x60,0x35,0xfe,0xff,0xd5,0x78, -0x48,0x60,0xe2,0x9e,0x41,0xe1,0xf0,0x83,0x65,0x5c,0x1a,0xa7,0x28,0xf3,0x2a,0xfc,0xf3,0xa3,0x24,0x47, -0xe6,0xf6,0x28,0x59,0xda,0x03,0xd5,0x70,0x2d,0x91,0xeb,0x48,0x0e,0x1c,0x0c,0x7f,0x20,0xf6,0x8b,0x9c, -0xb0,0x99,0xf0,0x4a,0x84,0xe0,0x0c,0x53,0x4f,0xa4,0xec,0x9e,0x51,0xce,0xad,0x51,0xb6,0xea,0xe9,0x8c, -0x72,0xae,0x47,0x99,0xdd,0xe0,0x01,0xf0,0x7d,0x8b,0x4c,0x8a,0xa7,0x9c,0x3b,0xb0,0xb1,0x38,0x5b,0x09, -0x0b,0xa7,0x4b,0xe3,0x7d,0xd5,0x1d,0xde,0x1a,0x66,0x04,0x32,0xb6,0xc0,0x0f,0x93,0x8a,0x10,0xeb,0x9d, -0x39,0x0d,0x03,0x4f,0xdd,0x34,0xbd,0x56,0x72,0xc0,0x06,0xb8,0x81,0xfa,0x4a,0x77,0xa0,0x98,0x4e,0xd1, -0x44,0x32,0xf5,0x67,0xc8,0x27,0x03,0x08,0xee,0xfd,0xf2,0x8b,0xd9,0x53,0x7e,0xf9,0xc5,0x33,0x5e,0xfe, -0xf6,0xa8,0x2a,0x79,0x67,0xef,0x40,0x03,0x72,0x56,0xf8,0x44,0xcf,0x8b,0x1c,0x01,0xb0,0x9b,0x71,0xc0, -0x70,0x64,0xe2,0xb3,0xa0,0xda,0xd5,0xbf,0x5c,0xe3,0x91,0x92,0x76,0x61,0xda,0xa5,0x98,0x76,0x7a,0xce, -0x97,0x7a,0xce,0xb7,0xa7,0xba,0x2f,0x73,0x1d,0x0b,0x41,0xa6,0xbb,0x99,0xd5,0x35,0x66,0xb3,0x89,0xf6, -0xad,0x26,0xd7,0xee,0xa1,0x66,0xf1,0x1e,0x12,0xe7,0x76,0x5c,0x8a,0xb7,0xa0,0x45,0xaa,0x89,0x2d,0xdf, -0x46,0x4a,0xb4,0xfb,0x84,0x91,0x63,0xb7,0xd6,0xfa,0x44,0x0e,0x20,0xce,0x9c,0xeb,0x13,0x5f,0x2a,0xe6, -0x2a,0x1b,0x77,0x9c,0x7c,0xd8,0x34,0xa8,0x9c,0xb8,0x93,0xcf,0xcc,0x4f,0xaa,0x9a,0x1f,0x10,0x03,0xae, -0xce,0x34,0xd9,0x24,0x8b,0x61,0x6d,0x60,0x6c,0xed,0xd4,0x6a,0xa1,0xe7,0x03,0xbc,0x70,0x6d,0x3f,0x20, -0x04,0xf6,0x4d,0xc8,0xdd,0xac,0xcf,0xf7,0x4b,0x07,0xb2,0xa6,0x6f,0xa9,0xef,0x3d,0x8e,0xd5,0x82,0x0f, -0xa8,0x5c,0xcb,0x8a,0x40,0x01,0x70,0x75,0x9e,0x6b,0xce,0xa6,0xb5,0x21,0xb2,0xe2,0x59,0xf1,0x72,0xb5, -0xed,0xfe,0xdd,0x4c,0xc3,0x2c,0xf4,0xf8,0x30,0xc4,0xa6,0x7c,0x9c,0x97,0x9c,0x8d,0x32,0x4c,0x19,0x9a, -0xed,0x13,0xdf,0xad,0x46,0xd6,0x57,0x87,0xec,0xd6,0x0a,0x9c,0x77,0x2b,0x00,0x21,0x3f,0xcf,0xd8,0xa6, -0xf8,0x60,0x92,0x47,0xf4,0x38,0x53,0x82,0x8f,0x5e,0x6b,0x20,0x4d,0x18,0x1f,0xd6,0xa0,0xe0,0x91,0x8a, -0xc9,0x83,0x3e,0x03,0xba,0xbc,0x12,0x9a,0xb9,0xec,0xb5,0xae,0x63,0xa4,0x41,0x76,0x3f,0x92,0xdb,0x54, -0xb5,0xb2,0x1d,0xf1,0x77,0x59,0x77,0xff,0xbd,0xaf,0x7d,0xf3,0x38,0x98,0xb8,0x02,0x7f,0xdc,0x92,0x2d, -0xcf,0x5d,0x10,0x1b,0x65,0x33,0x41,0x47,0xa6,0x36,0x33,0x57,0xc5,0x4a,0x86,0xb4,0x6f,0xd0,0xa3,0xd9, -0xb0,0x61,0x15,0x57,0x7c,0xc0,0x8f,0xa6,0x00,0x22,0xac,0x26,0xc9,0xa0,0x89,0x27,0x3b,0x16,0x92,0x96, -0x1c,0x8d,0x26,0x8b,0x88,0x5e,0x45,0xb4,0xc2,0x8e,0x16,0x62,0x19,0x85,0x68,0x05,0xec,0x2d,0xea,0x37, -0xc2,0xa2,0xf5,0xba,0x04,0xb6,0x14,0x3c,0x82,0x72,0x83,0x56,0x05,0x14,0xff,0xdc,0x66,0xff,0xf4,0x8b, -0xf5,0x7a,0x37,0xf3,0xed,0x37,0xb0,0x47,0x16,0x8c,0x5e,0x0e,0x17,0xc1,0xce,0x9d,0xe7,0x38,0xcb,0xca, -0xaa,0x08,0x1b,0x28,0xa0,0xf1,0x4a,0x04,0x92,0xb5,0xd9,0x85,0x56,0xdd,0xd8,0x38,0x8e,0xf3,0x09,0xab, -0x8c,0x75,0xef,0x14,0xb2,0x44,0x74,0xc8,0x00,0x86,0xef,0xcf,0x8c,0x95,0x14,0x84,0xfa,0x74,0xaa,0xc0, -0xa1,0xd2,0x2f,0x1b,0x26,0xdb,0x72,0xd7,0xb1,0xe6,0xa4,0xca,0x93,0x27,0x59,0x19,0x48,0x3c,0xde,0x80, -0xb5,0x4b,0x00,0xe4,0xd3,0xa3,0xca,0x8e,0xfb,0xce,0x78,0x20,0x76,0x33,0x6c,0xd2,0x5d,0xee,0x57,0x09, -0xcf,0x1a,0x81,0x5d,0x9b,0x2b,0x75,0x96,0xe3,0xac,0x7b,0xba,0xe7,0x5e,0xeb,0x18,0x84,0x19,0x61,0x85, -0xf2,0xbf,0x76,0xdb,0x42,0xb3,0x48,0x75,0x30,0x53,0x53,0x60,0x02,0x1a,0x29,0xa1,0x1c,0x39,0xdc,0x52, -0xd1,0xd6,0xbe,0x00,0x4c,0x4a,0x4c,0xe4,0x0a,0xae,0x7c,0x3d,0xc3,0x27,0x5e,0x91,0x13,0xcd,0x51,0x22, -0xc0,0x40,0x11,0xe8,0xc7,0xea,0x68,0xad,0xd0,0x9b,0xf8,0x67,0xad,0x91,0x96,0x18,0x9b,0x49,0xcc,0x16, -0xd4,0x32,0x3b,0x57,0x8e,0xbb,0x61,0x17,0x7b,0xe9,0x36,0xd0,0xce,0x78,0x5a,0xae,0xd7,0x79,0x0a,0x08, -0xcd,0x53,0x4d,0x77,0x43,0x91,0xd5,0x10,0xc3,0xc0,0xeb,0x00,0x00,0x0e,0xf6,0x4b,0x83,0x16,0xc0,0x29, -0x1a,0x20,0xbd,0x06,0x6e,0x93,0x16,0x0c,0x58,0x80,0x24,0xae,0xe2,0x32,0xe6,0xfc,0x43,0x1c,0x9b,0xcb, -0x96,0xed,0xb8,0x7d,0xbf,0xfb,0x58,0x9d,0x11,0xe7,0x03,0xdd,0x92,0x06,0x12,0x17,0xb3,0x66,0xde,0xb0, -0x6b,0x43,0x66,0xd4,0xe8,0xd9,0x45,0x3c,0xb7,0x4a,0xa5,0x26,0x5c,0x98,0xb8,0x11,0x17,0x0a,0xf2,0x13, -0x36,0xe6,0xd6,0xa7,0x91,0x30,0xde,0xe8,0xf0,0xc1,0x1c,0x51,0x84,0x1c,0xc4,0xae,0xda,0x85,0xe8,0x99, -0x87,0x1d,0xeb,0x03,0x9c,0x11,0xd9,0x97,0xae,0x7a,0x2b,0x95,0xa3,0x6d,0xe8,0x5e,0xf4,0x59,0x68,0xf5, -0x43,0x6c,0x61,0xc8,0xd2,0xf3,0x06,0x69,0x30,0xb6,0x12,0x4d,0xfe,0x24,0x64,0xa8,0x08,0x6c,0x6a,0x0d, -0x16,0xa8,0xc2,0x87,0xd6,0x0a,0x0c,0x09,0xfb,0x87,0x06,0x55,0x2a,0x19,0x1b,0x5b,0x91,0x67,0x98,0xbc, -0x3b,0xeb,0x3a,0x0f,0x59,0xe6,0xb0,0x1d,0x08,0x35,0x23,0x12,0x74,0xa6,0x47,0x60,0xbd,0x36,0x97,0x8d, -0x5b,0x99,0x42,0x81,0x14,0x59,0x61,0x46,0x23,0x78,0x36,0xd4,0x78,0x66,0xda,0xa0,0xe2,0x07,0xea,0xf7, -0xe2,0x0a,0xc1,0x94,0x98,0xde,0xac,0x62,0x17,0x59,0x15,0x68,0xaa,0x7a,0xd8,0x57,0x83,0xb9,0x60,0x28, -0x27,0x16,0xd5,0x0b,0xc6,0xc9,0xb8,0xf5,0x44,0x81,0xd6,0xb2,0xfb,0x52,0x32,0x06,0x60,0x19,0x0c,0x15, -0x6c,0x47,0x33,0x4c,0xb7,0x00,0xd0,0xa5,0x9c,0xb0,0xb2,0xfd,0xce,0xd6,0x6b,0xed,0x65,0x28,0x35,0x23, -0xfe,0x2d,0xd8,0x08,0x10,0xc0,0x68,0x4c,0x65,0x2f,0xa7,0x85,0xc2,0x94,0xac,0xb7,0x42,0x54,0xd6,0x0a, -0x65,0xe4,0xfe,0xe1,0x64,0x65,0x41,0xc3,0xa2,0x2d,0xa7,0x06,0xda,0x33,0x69,0xe3,0x7a,0xca,0x57,0x33, -0x03,0x86,0x9b,0x68,0xbc,0x51,0x9a,0x23,0xa7,0x80,0x6a,0x94,0x6e,0x4d,0x20,0x4d,0x3c,0x45,0x6c,0xd8, -0x04,0xe0,0xa5,0xcd,0x9b,0xbd,0xbd,0x97,0xa9,0x8f,0xdd,0xc3,0x37,0x63,0xef,0x7c,0x63,0x9e,0x2a,0x1d, -0x7d,0x07,0x6f,0xa9,0x91,0xd8,0x48,0xfd,0xe7,0x18,0xe1,0xba,0x07,0xc3,0x09,0xfa,0xb2,0x33,0x63,0x67, -0x02,0xdc,0x56,0x63,0x20,0x28,0xe5,0x51,0xc7,0xb2,0x8e,0x2c,0xd7,0xa8,0xad,0xbb,0x2f,0x53,0x8e,0x95, -0xb7,0x68,0xc7,0x5e,0x2e,0x01,0xd5,0xda,0x99,0x0b,0x1c,0xf7,0xb6,0x44,0xf3,0x2a,0x9c,0x80,0xe9,0x42, -0x22,0xe9,0x85,0xdd,0x75,0x4f,0xb5,0x44,0x1e,0x7e,0xef,0x3b,0x35,0xf7,0x4d,0x26,0x55,0xd0,0x74,0x03, -0x98,0x02,0x05,0xbb,0xb4,0xc5,0x54,0xa2,0x21,0x9c,0xf6,0x92,0x47,0x00,0x17,0x26,0x79,0xa9,0x0b,0x92, -0x35,0xda,0x04,0xe3,0x76,0x15,0xb0,0x06,0x78,0x31,0xf6,0xc4,0x68,0xe9,0x90,0xe0,0x36,0x4a,0xdb,0x76, -0xe8,0x12,0x9d,0x3b,0x6a,0x6b,0xdc,0xc8,0xd5,0xc3,0xa7,0x0a,0xfb,0x7a,0x9b,0x0d,0x1a,0x98,0x73,0xcb, -0xb3,0x60,0xa7,0x37,0xd3,0x9c,0x11,0x14,0xac,0xbd,0xd5,0xc3,0x66,0xb2,0xc3,0x3b,0xcb,0x8e,0xda,0x6c, -0x76,0xf4,0x3e,0xb3,0x43,0xfd,0x99,0xfd,0x91,0xee,0x88,0xfd,0xe0,0x0e,0x03,0xf0,0xed,0xcc,0x4f,0x16, -0x72,0xc1,0xa0,0x42,0x80,0xf4,0x95,0xab,0xd5,0x52,0x7e,0x71,0x58,0xdb,0x31,0x38,0x44,0x3b,0x1a,0x7a, -0x68,0xa7,0x81,0x29,0xda,0x69,0xa0,0x89,0x76,0x04,0xb2,0x6a,0x47,0x05,0x5d,0xa8,0x56,0x27,0x97,0x59, -0xbd,0xf3,0x5b,0xfa,0x9e,0xf3,0xa5,0xdf,0x25,0x82,0xc3,0xe0,0x82,0xb2,0xb7,0x70,0xe8,0x3d,0xcb,0x30, -0xbd,0x57,0x17,0xed,0x4a,0xcd,0x1b,0xd1,0x7e,0x47,0xc6,0x3c,0x92,0x83,0xb1,0x6c,0x94,0xe2,0xec,0xac, -0x6d,0x76,0x75,0xbf,0xf5,0x8d,0xf1,0x05,0x1a,0x77,0xcb,0x08,0x37,0xad,0x05,0x17,0xd1,0x34,0x18,0x50, -0xd7,0x62,0xfd,0x46,0xbc,0x84,0xea,0xef,0x98,0x36,0x24,0x8d,0xd2,0x08,0xfc,0x1c,0xeb,0x95,0x32,0xde, -0x86,0xfe,0x5f,0x10,0x22,0x0d,0x9c,0xa3,0xa0,0x39,0xda,0xe0,0x8b,0x7d,0xf3,0xa2,0xa5,0xb3,0x56,0xc4, -0x5e,0x4d,0x6d,0x68,0xe2,0x35,0x90,0x9e,0x79,0x29,0x30,0xc6,0xc1,0x66,0xdc,0xd9,0x1b,0x6a,0x61,0xab, -0x56,0x96,0xb4,0x5c,0xaf,0x27,0xe9,0x42,0x97,0x0e,0xcb,0xe9,0xc6,0x8a,0x48,0x55,0x42,0x2b,0x4c,0x74, -0xa7,0xec,0xa2,0x9e,0xa7,0x32,0x2f,0x43,0x27,0x31,0xc7,0xec,0x1e,0x05,0x83,0x43,0x06,0xf3,0x10,0xf4, -0xe8,0xff,0x46,0xd1,0xfb,0x87,0xe3,0x6c,0xe2,0x16,0x90,0x21,0x60,0x78,0x2f,0xde,0xa2,0x55,0x21,0x05, -0x85,0x82,0x2c,0xd8,0xe3,0x84,0xd9,0xb3,0xdf,0x20,0x9f,0x5a,0x14,0xa7,0xbc,0x3f,0x84,0x6f,0x1a,0x43, -0x84,0xf0,0x5b,0x9c,0xac,0x27,0xcc,0x9b,0xb1,0x70,0xfc,0xc7,0x17,0xcf,0xbb,0xee,0xd1,0x2c,0x2d,0x03, -0xe8,0x79,0xdb,0xfe,0xca,0x00,0x9c,0x62,0x2a,0xb2,0xef,0x7f,0x1e,0x33,0x8d,0x4a,0x87,0x8f,0x5e,0xbe, -0x78,0x85,0x0c,0xcb,0x40,0x32,0x7e,0x52,0x16,0x97,0x6f,0xf8,0x73,0xe6,0xd9,0x68,0x62,0x1e,0x5c,0x5f, -0x2e,0x3c,0x1d,0xb6,0xbc,0x0c,0xe8,0x53,0x75,0x22,0x6b,0x1c,0xae,0x77,0x99,0x21,0x57,0xfa,0xea,0xea, -0xeb,0xf7,0x6f,0x93,0x73,0x9c,0x1a,0x7d,0x8f,0xb3,0x2c,0x53,0xc4,0x14,0xf6,0x02,0xdb,0x2c,0x22,0x95, -0xd0,0xf0,0xcf,0x72,0xe2,0x4f,0x29,0x33,0x6a,0x0e,0x07,0xfc,0x85,0xda,0x8b,0x7b,0xe2,0x11,0xda,0x3b, -0x3d,0x9e,0xdd,0x39,0x08,0x7f,0x65,0xa1,0xc2,0xe4,0x38,0x3f,0x38,0x0f,0x1f,0x28,0xfe,0x55,0x56,0xb4, -0x52,0x1a,0xad,0xb3,0xcb,0xe4,0x3c,0x5d,0xd3,0x92,0x26,0x6e,0xe5,0x2c,0x5b,0xa4,0xac,0x45,0xfa,0xfd, -0x56,0x75,0x13,0x2d,0xfd,0xf3,0x34,0x0f,0x44,0xb5,0xc4,0x60,0x4c,0x71,0xcf,0x44,0xd7,0x4e,0xf4,0x5b, -0xcc,0x77,0x5a,0x61,0xc7,0x11,0x9a,0x66,0x5c,0x4e,0xb5,0xfd,0xd3,0x2c,0x4e,0xf3,0x53,0x62,0x2f,0xbe, -0x7b,0xfd,0x0c,0x2e,0xda,0x74,0x0c,0x64,0xc0,0xd6,0x81,0x17,0x7b,0x83,0x9e,0x37,0xce,0xa9,0x77,0xd3, -0x75,0x34,0x49,0xd9,0x5b,0xe8,0xd7,0xdf,0x11,0x2f,0x59,0xef,0x7f,0xaf,0x16,0x49,0x96,0x1b,0x93,0xc3, -0x40,0x2f,0xea,0xd4,0x3e,0xc5,0x08,0xf6,0xa9,0x84,0xfa,0x6b,0x04,0x01,0x38,0x10,0x18,0x63,0xb7,0x5c, -0xf0,0xb5,0x7e,0x22,0x0e,0x2e,0x05,0x8e,0x31,0xa6,0xb0,0xd1,0xf9,0x29,0xf6,0x71,0xcf,0x0b,0xda,0xf6, -0x97,0x34,0xb2,0xb4,0x80,0x89,0x92,0xf7,0xb8,0x00,0xeb,0x5e,0xd5,0xa1,0x3f,0x55,0x4a,0x69,0x4a,0xc0, -0x76,0xf2,0xf6,0xa3,0x3e,0x27,0xe2,0x8b,0x2e,0x74,0x87,0x58,0x72,0x68,0xdd,0xbc,0x88,0xc5,0x52,0x35, -0xeb,0x9a,0x43,0x3d,0x6b,0xef,0x1b,0xb6,0x54,0x49,0x32,0x37,0x81,0xb6,0x05,0xed,0x64,0x68,0x64,0x30, -0x8e,0x23,0x07,0x7a,0x8c,0x3b,0x5a,0x89,0x8a,0xb2,0x8a,0x58,0x7d,0x7d,0x98,0x86,0x37,0xd9,0xef,0xda, -0x23,0xd1,0x16,0xd5,0x80,0x37,0x79,0x60,0x61,0x75,0xc8,0xdb,0x53,0x0d,0x49,0xb5,0xfb,0x9d,0xc6,0xe7, -0xe3,0xc8,0xf3,0x4e,0xfb,0x9c,0xc9,0x65,0xcb,0xa7,0x5c,0xd8,0x40,0x31,0x10,0x88,0x3a,0x61,0xfa,0x94, -0x18,0x2a,0xef,0x11,0x43,0xdd,0xa0,0x2d,0x91,0x1c,0x15,0x14,0xea,0x70,0x83,0xd1,0xf5,0x2b,0xad,0x73, -0x80,0x8e,0x01,0xd3,0x36,0x88,0x7a,0x92,0xe6,0xfd,0x49,0x05,0x02,0xc2,0xc4,0x1a,0xa7,0xe5,0xf6,0x97, -0x7b,0x23,0x5a,0xa3,0x4f,0xe9,0xea,0x93,0xe1,0x5d,0x5a,0xb9,0x4f,0xe8,0xca,0x9f,0x4e,0xf6,0x66,0xc1, -0x2f,0xf1,0xf4,0xe7,0xbd,0xd9,0xdd,0x83,0xf0,0x25,0xaf,0xca,0xe1,0xdd,0x09,0x9d,0xe7,0x76,0x8e,0xeb, -0xd9,0x5d,0x7f,0xfa,0x33,0x72,0x44,0xc4,0xae,0x83,0xf3,0xcb,0xf0,0x95,0xd6,0xfd,0x9e,0xd0,0xee,0xb3, -0x26,0xe6,0x10,0xff,0xef,0x57,0x75,0x51,0x62,0x89,0x0f,0x07,0xfb,0x3c,0xf9,0x2a,0x6a,0x1d,0xaf,0x74, -0x2c,0xfa,0xf5,0x55,0x36,0x67,0xb8,0x55,0x2a,0xf1,0xb5,0xfa,0xfc,0x9b,0xc7,0x6f,0xd7,0x4f,0x1f,0x3f, -0x78,0x04,0xb3,0xfc,0x17,0x8c,0x73,0x76,0x70,0x7c,0x70,0x10,0x3e,0xe3,0xf0,0xc1,0x3f,0xf0,0xdf,0x3b, -0x75,0xec,0xdd,0x3d,0xf0,0x00,0x2c,0x46,0xa4,0xcd,0xf7,0xee,0x22,0x58,0x58,0x9f,0x29,0x50,0x42,0x33, -0xeb,0xeb,0x9a,0x15,0x8b,0xf1,0x6f,0xf2,0xeb,0xd8,0xa4,0x9c,0x02,0xf4,0x21,0x1a,0x85,0x88,0x91,0xf3, -0xa2,0x98,0x67,0x67,0x19,0x71,0x77,0xb0,0xe3,0xad,0x93,0x73,0x0e,0x4e,0xf3,0x6b,0x72,0xfd,0x26,0xad, -0x6b,0x22,0xa9,0x55,0x74,0xb3,0x2a,0x17,0x91,0xce,0x85,0xb9,0x42,0x8f,0xea,0xea,0x11,0x67,0xf8,0x9c, -0xc8,0xfe,0x22,0x7a,0xa5,0xa6,0xce,0x6f,0xca,0x31,0xe6,0xb4,0x00,0x13,0x2b,0x81,0x6e,0x00,0x57,0x59, -0x16,0xd8,0x66,0x18,0xdd,0x8b,0x6e,0x93,0xea,0x7d,0x7e,0xaa,0x50,0xa6,0xa1,0x5d,0x13,0xe4,0x64,0xb0, -0xd4,0x99,0xec,0x21,0x07,0xd7,0xfb,0x57,0x57,0x57,0xfb,0xb4,0xc8,0x2f,0xf7,0xa9,0x64,0x21,0x3b,0xf3, -0x31,0xf8,0xa3,0x12,0x3e,0x72,0xdf,0xbd,0x7d,0xb2,0xff,0x37,0x8f,0x43,0xff,0x2e,0x6b,0xe5,0x8d,0x70, -0xa7,0x16,0x90,0x2b,0x21,0xfe,0x4b,0x90,0x18,0x4f,0x70,0x71,0xe4,0x09,0x2e,0xbd,0xf0,0x1a,0xf7,0x4e, -0x49,0x97,0x8b,0x70,0xc7,0xec,0x17,0xe1,0xaf,0x15,0xbb,0xf0,0x5b,0x09,0xf0,0x44,0xa5,0x40,0xbc,0x2c, -0x85,0x59,0xb6,0xd1,0x75,0xa7,0xd2,0x91,0xe7,0xc1,0xf1,0x09,0xfd,0x1c,0x9f,0x1c,0x48,0x91,0x74,0x8b, -0xdf,0x03,0xc9,0x8f,0xee,0xf0,0x4b,0x6f,0xa1,0xa7,0xaa,0x88,0x72,0xd2,0x86,0x95,0xa5,0x8b,0xb9,0xfa, -0xd8,0xd3,0x0f,0x69,0x3f,0xf1,0x54,0x2b,0xf4,0x23,0xa0,0x36,0xe8,0x6a,0xe9,0x67,0x7f,0x7f,0xf3,0xf2, -0x5b,0xa9,0x01,0xb1,0x5d,0xb5,0xf2,0xc7,0xe0,0x2a,0x7a,0x91,0x6c,0x82,0xb2,0x05,0xee,0x70,0x9b,0x19, -0xa5,0x94,0x6f,0x91,0x8b,0x17,0xe1,0x6b,0xd9,0x34,0xd5,0x63,0x34,0x3c,0xb2,0x76,0x68,0x62,0x9e,0x88, -0x21,0x7a,0x29,0x52,0x30,0x19,0x7a,0x3d,0x56,0xd7,0x70,0xba,0xdf,0x98,0xc9,0xb1,0xda,0x62,0xcf,0x50, -0x4f,0xfe,0xe1,0xff,0x83,0x9e,0xc0,0xc8,0xc8,0x9a,0x46,0x10,0x1d,0x45,0xff,0xf0,0x5b,0x4f,0x19,0x9f, -0x0c,0x0f,0x1a,0x70,0xbe,0x7f,0xfa,0xcf,0x20,0x6d,0xa3,0x67,0x6f,0xcb,0x24,0xa7,0x46,0x97,0x35,0x3d, -0xfb,0x41,0x3d,0x73,0xa4,0x39,0x16,0x06,0x4a,0xa9,0xa4,0x3b,0x95,0x90,0xa3,0x05,0x87,0x61,0x39,0x09, -0xaf,0xc2,0xb7,0x71,0x3e,0x3e,0x45,0x7c,0x18,0xd8,0x15,0xae,0xa0,0x6e,0x77,0x4c,0xef,0x56,0x70,0x7f, -0x54,0x47,0xa8,0x24,0xae,0xa0,0xa1,0x08,0x1f,0x5a,0xf1,0xe1,0xe3,0x9a,0xf8,0xe2,0xcf,0xb1,0x54,0xe8, -0x2a,0xbe,0x37,0x1a,0xd1,0xa1,0xf2,0xe8,0xb3,0xd1,0x68,0xbd,0xfe,0x6c,0xf4,0x39,0xe4,0xf6,0x21,0xa2, -0x16,0x9c,0xc4,0xff,0xf2,0x2f,0xc2,0x87,0xec,0x7c,0x7d,0x12,0xa7,0x29,0xdd,0x9c,0xd0,0x2d,0xad,0x83, -0xc5,0xc4,0xbf,0x18,0x66,0x67,0x7a,0x91,0x51,0xda,0xab,0xf8,0x21,0xc8,0xd0,0x6b,0x35,0x9e,0x4f,0xa9, -0x28,0xc4,0x84,0x7f,0x4e,0x4b,0x71,0x5f,0x27,0xa3,0x75,0x7d,0x25,0x38,0x3f,0xf6,0x0a,0x45,0xd4,0xbb, -0x2b,0x7a,0xd3,0x9f,0x01,0xd6,0x6e,0xf3,0x1d,0xee,0x24,0x7d,0x10,0xde,0x93,0x9a,0x52,0xdb,0x40,0x5f, -0x20,0xd8,0xbd,0x10,0x0c,0xec,0xb7,0xb1,0x97,0x17,0x6a,0x2e,0x7b,0x91,0x6a,0x90,0x3c,0xad,0x2f,0x75, -0x55,0x22,0xff,0x6d,0x7c,0x02,0x6b,0xcd,0x3a,0x0d,0x97,0x74,0xc5,0xc1,0x1f,0xe6,0x74,0xc1,0xfc,0x10, -0xf5,0xcb,0xee,0x3c,0x20,0xee,0x71,0x1e,0xbf,0x0d,0x61,0xee,0xfd,0x96,0xfa,0x9a,0x72,0x10,0xfe,0x29, -0xac,0x59,0xbd,0x5b,0xc7,0x23,0x04,0x27,0x7f,0xc8,0xb9,0xac,0xe0,0x66,0xa9,0x2f,0x19,0x97,0xc4,0x27, -0xe6,0xfe,0x2d,0x31,0x19,0x1e,0xf5,0xd6,0x7b,0x27,0x14,0xe4,0x79,0x38,0x5d,0x86,0x6f,0xc3,0x87,0xb3, -0x20,0xc2,0x0b,0x30,0x0d,0xfa,0xf9,0x43,0x7a,0x4e,0xc7,0x6a,0x93,0x13,0xf0,0x65,0xfd,0xeb,0x20,0xbc, -0xd6,0xa3,0x79,0xb6,0xb7,0xf7,0xce,0x1c,0x5c,0x16,0x13,0x8f,0xa7,0xdd,0x8a,0x59,0x5e,0x2f,0xe2,0xbb, -0xc7,0x52,0x47,0xca,0xea,0x82,0x4a,0x5e,0x46,0xc8,0xee,0x92,0x43,0xa2,0x5a,0x85,0x40,0x3a,0x44,0x4d, -0x68,0xb2,0xe2,0x4f,0x1f,0x2a,0xb7,0x11,0xf9,0x9a,0xd2,0xec,0xef,0x63,0x66,0x33,0x5d,0x15,0x66,0xd1, -0x39,0x6f,0x4a,0xe1,0x75,0xc1,0x52,0xeb,0x4d,0x9f,0x34,0xad,0x03,0xf2,0x99,0x73,0x70,0x13,0x0b,0x5f, -0xc0,0x0d,0x30,0x14,0x37,0x0b,0x69,0xb5,0x84,0x0b,0x46,0x4e,0x34,0x37,0xbe,0x18,0xaa,0x95,0xba,0x5e, -0x5f,0x84,0xef,0x9a,0x5b,0xcc,0x09,0x1b,0x43,0x52,0xf1,0x64,0x1c,0x79,0xf0,0x9c,0x35,0xa4,0x22,0x33, -0x7d,0xdf,0x8a,0xdf,0x79,0x89,0xfb,0x6d,0x01,0x5c,0xa9,0xab,0x2f,0xac,0xce,0x67,0x71,0xd9,0x09,0xb6, -0xa9,0x2b,0xfc,0xa1,0x39,0x20,0x90,0xcc,0x88,0x24,0xf7,0x30,0xbe,0x69,0x96,0x54,0xc4,0x01,0x13,0xdc, -0xe9,0xdb,0xe3,0x21,0x49,0xdc,0xe4,0xa9,0x08,0xd5,0x04,0xa4,0x11,0xb1,0xc6,0xc6,0x75,0xfc,0x52,0x05, -0x3d,0x4a,0x10,0xce,0x64,0x5a,0x77,0xe1,0xc3,0xe2,0x7a,0x7a,0x0f,0x4a,0x54,0xf8,0x14,0xba,0x6f,0x36, -0x0e,0x4f,0x52,0x0b,0x4f,0x52,0x73,0xa8,0xfa,0x07,0x8b,0x85,0x5b,0xa1,0xaa,0x87,0xbd,0x3b,0x55,0x86, -0x62,0xac,0x47,0x78,0x0d,0x87,0x86,0xaa,0xee,0x54,0xdf,0xa2,0x84,0x52,0xce,0x29,0xfb,0x31,0x5c,0x75, -0x6a,0xd3,0xf3,0x08,0xa1,0x3b,0x4f,0x60,0x3c,0xae,0x34,0xb0,0x9b,0x10,0x67,0xeb,0x32,0x9b,0xa7,0x2f, -0x88,0x5c,0x49,0x10,0xa6,0x6d,0x42,0x75,0x14,0x73,0x31,0xbc,0x54,0xe9,0xe2,0x54,0xe7,0xd0,0x0c,0x50, -0x7f,0x1f,0xa7,0x01,0x77,0xf4,0xc3,0x61,0xb2,0xb8,0x4a,0xde,0x57,0x7e,0x3a,0xd5,0x2b,0xca,0xf6,0x2d, -0xa9,0x85,0xdd,0x86,0xd9,0x56,0x3c,0xbd,0x66,0x83,0x72,0xfa,0xe3,0x78,0x11,0x13,0x1d,0x3f,0x01,0xad, -0xee,0x31,0x04,0xa2,0xe5,0x6d,0x61,0x17,0x67,0x43,0x4e,0x08,0x9d,0x4a,0xe9,0x8f,0xb4,0xb6,0x79,0xc3, -0xe7,0x87,0xf7,0x26,0xe6,0xea,0x43,0xc8,0xae,0x69,0xfb,0x89,0x7d,0x08,0x0a,0xf8,0x72,0xbd,0x56,0x5c, -0x08,0x68,0x45,0x60,0x38,0xbc,0x17,0x75,0x68,0xb1,0x1e,0x03,0xef,0xe0,0xc0,0xc3,0xb7,0x2c,0xde,0xcb, -0x87,0x97,0x69,0x7d,0x51,0xcc,0x61,0xf1,0x2e,0x31,0x52,0x2e,0xcc,0x13,0x49,0x42,0x29,0x41,0xd1,0xd0, -0x69,0x55,0xec,0x37,0x37,0x44,0x2d,0x89,0xbd,0x72,0x07,0xa8,0x13,0x96,0x4b,0xba,0x9e,0x96,0x59,0x59, -0x10,0x87,0x53,0x5c,0x12,0xdf,0x11,0xdc,0x2c,0xb6,0x30,0x64,0x38,0xc3,0x2e,0x84,0x27,0xe3,0xe6,0x84, -0xea,0x46,0x7e,0x42,0x27,0x97,0xf8,0xeb,0x56,0x8b,0x06,0x60,0xe7,0x8a,0xaa,0xde,0x45,0x74,0x18,0xe7, -0xc5,0x82,0x9f,0xab,0xb3,0xee,0xe3,0xe0,0xc6,0xcd,0x07,0x3b,0x36,0xf5,0xab,0xb4,0x6b,0x6f,0xef,0x62, -0x68,0xb1,0x63,0x8d,0x39,0x85,0x39,0x75,0xeb,0x74,0xea,0x83,0xd8,0x9c,0x89,0xe4,0x1e,0xdd,0x0a,0x05, -0x14,0xc6,0x37,0x59,0x10,0x49,0xff,0x3b,0x6d,0xd6,0x44,0x3d,0xf3,0x90,0x86,0xeb,0x54,0x9f,0xd8,0x1f, -0x8e,0x1b,0x79,0x3a,0x8a,0x14,0x5e,0x10,0x64,0x74,0x24,0xe8,0x18,0x42,0x27,0x07,0x83,0x6e,0xd8,0x3f, -0x4d,0x29,0x93,0xb2,0x6e,0x06,0x51,0x7e,0x68,0x28,0xbe,0x5b,0x2e,0xf5,0x50,0xd0,0x3b,0xd8,0x10,0x28, -0xe8,0xc5,0xdd,0xd7,0x8a,0x07,0x95,0xa4,0xb0,0xaa,0xe0,0x2e,0x36,0x73,0xe4,0x29,0xab,0x69,0x9d,0x8f, -0x26,0x5b,0xfa,0x84,0x11,0x62,0x14,0xe5,0x14,0xf6,0x54,0xa2,0xa8,0x19,0xdd,0xc9,0x07,0x79,0x55,0x86, -0xed,0x50,0x1d,0x28,0x3f,0xa6,0x1e,0xcf,0xa9,0x1e,0x03,0x4f,0xf6,0x4b,0xa9,0xa1,0x44,0xaa,0xd1,0xea, -0xd4,0x20,0x34,0x23,0x50,0x0c,0x62,0xff,0x5b,0xd5,0xac,0x22,0x98,0xd0,0x69,0x36,0xf2,0x26,0x5e,0x30, -0x50,0x23,0xa1,0x4c,0x3b,0xe5,0x0e,0x9f,0x9d,0xd2,0x31,0x3a,0xd5,0xd8,0xd0,0x45,0x5c,0x98,0x32,0x9f, -0x50,0x99,0x77,0x0e,0x59,0x2f,0xd4,0x9b,0xa1,0xf7,0x0b,0x9d,0xee,0xdf,0xd4,0x83,0xc1,0xce,0x60,0xae, -0x17,0x5d,0x21,0x97,0x0e,0xe3,0xd2,0xe5,0x46,0xf6,0xf6,0x1e,0x0e,0xdb,0xa4,0xd0,0xf7,0x9e,0x9d,0x19, -0x3e,0x66,0xff,0x4d,0x46,0x5b,0x80,0x17,0x76,0x3f,0x15,0xb1,0xab,0x30,0x29,0x5b,0xb3,0xf9,0xb6,0xc8, -0x53,0xb8,0x45,0x9f,0x5e,0x78,0x56,0x72,0x9a,0x76,0xd6,0x7c,0x6e,0x06,0x14,0x77,0xd6,0xa8,0x29,0xa9, -0x7c,0x6e,0x3f,0x0b,0xfa,0x8b,0x52,0x19,0xec,0xbf,0x65,0xd3,0x6c,0x27,0x17,0x66,0x30,0x3a,0x1f,0x3c, -0xe0,0xc3,0x87,0x67,0xd3,0x0e,0x8e,0xd8,0x7d,0x31,0x54,0xc7,0x92,0xa9,0xfb,0x66,0x36,0xd9,0xfa,0x66, -0x80,0x63,0xdc,0x6e,0x1c,0xbb,0x8f,0x27,0x5e,0xb8,0xe3,0x0d,0xee,0xd4,0x03,0x6f,0xbc,0xf3,0x7b,0x3c, -0x1a,0x8e,0x0e,0x69,0xb0,0xbc,0x20,0x6a,0xb2,0x61,0x0f,0x68,0xd6,0xbe,0x2f,0x41,0x9b,0xa9,0x23,0x64, -0xdf,0x0a,0x7a,0xea,0xbb,0x0c,0xcd,0xeb,0xe9,0x52,0xd0,0x9f,0x2f,0x86,0x82,0xe7,0xf8,0x86,0x0e,0x84, -0x3c,0x5b,0x9b,0x5b,0x51,0x70,0x9e,0x13,0xff,0x7a,0x21,0x31,0xb8,0xd6,0xeb,0x53,0xa3,0x20,0x7e,0xa8, -0x88,0x37,0x67,0x42,0x7b,0x3c,0xdf,0x79,0xc4,0x36,0x21,0x80,0xf6,0x85,0x71,0xa7,0x45,0xb7,0xcd,0x81, -0xc9,0x48,0x1c,0x82,0xf0,0x5c,0x78,0x72,0x96,0x64,0x0b,0x7a,0xc2,0xbc,0x21,0xf8,0xee,0xbf,0x13,0x5b, -0xaf,0xa8,0x07,0xef,0xf4,0x0e,0xe3,0x7d,0xe8,0x72,0x70,0x42,0x18,0x18,0x97,0x52,0xb1,0x5c,0x16,0xbd, -0xa1,0x6e,0xc1,0xb1,0x12,0x03,0x50,0x0b,0x63,0x0f,0xbc,0x69,0x7f,0xe5,0x3a,0xe3,0x58,0x3b,0xba,0x6e, -0x86,0xa7,0x92,0x43,0x52,0x64,0xbe,0x0d,0x84,0x56,0x9f,0xc2,0xa1,0x11,0x86,0xc6,0x74,0x64,0x3e,0x81, -0x97,0x96,0x21,0xb1,0xbc,0x63,0xd6,0x17,0x65,0x71,0xb5,0xf3,0x78,0x5c,0xfa,0xfb,0x87,0xe1,0xe3,0x60, -0x23,0xb1,0xf8,0xf8,0xce,0xfb,0xb6,0xd8,0x31,0x87,0x97,0x46,0xc8,0xf3,0x90,0x59,0x0d,0x1c,0xc1,0xb6, -0x99,0xdb,0x9f,0xa7,0xda,0x50,0x99,0x3a,0xc5,0xe3,0x23,0x1b,0x8b,0xb0,0xea,0x37,0x7c,0xf2,0xec,0x67, -0x33,0xcc,0x47,0x5a,0x0b,0xda,0x80,0x6b,0xbb,0xa6,0x03,0xb0,0x7e,0x09,0x3d,0x04,0xfd,0xe9,0xc1,0x6a, -0x6a,0xeb,0x09,0x1c,0x77,0x3e,0x57,0x70,0x98,0x8b,0x0d,0x11,0x04,0xd8,0x70,0xb6,0x0c,0x73,0xc3,0xb6, -0x2a,0xa6,0xd4,0xb7,0x64,0x0d,0x38,0x41,0xa6,0xa1,0xd2,0x9f,0xeb,0x29,0x1e,0x65,0x12,0xc6,0x34,0x0f, -0xd5,0xec,0x88,0xc4,0x53,0xba,0x2d,0x1e,0x84,0x0d,0xa4,0x6e,0xc4,0x2f,0xe9,0xbb,0x64,0xf1,0x1d,0xd1, -0xa6,0x1e,0x16,0x48,0x97,0x6b,0x97,0x26,0x42,0x0a,0x53,0xa2,0xee,0x93,0x90,0xe9,0xa4,0x25,0x89,0x38, -0x34,0xb2,0x0a,0x1a,0x38,0x1e,0xd4,0xca,0x63,0x4d,0x57,0x5b,0x76,0x78,0x55,0x26,0x4b,0x20,0x9c,0x6e, -0x05,0xf3,0x50,0xaa,0x27,0x21,0x95,0x2d,0xb7,0x7b,0xb8,0xb2,0x36,0xe6,0x5c,0x94,0x4a,0x59,0x55,0x29, -0x20,0x15,0x7a,0xe0,0x8a,0xee,0x83,0x61,0xfa,0xbb,0xaf,0xc3,0x25,0xb3,0x3b,0xa8,0x4e,0xe6,0xda,0x4c, -0x3b,0x10,0xc8,0x3a,0xeb,0xb0,0x6e,0x4b,0x21,0x0d,0xe8,0xb1,0xc4,0x98,0x4b,0x05,0x0f,0x5a,0xb1,0x27, -0xec,0x25,0x36,0x0e,0x50,0xc3,0xee,0x63,0x03,0x5d,0x61,0xc0,0x70,0xc5,0xd2,0x55,0xb1,0x97,0xe8,0x94, -0x67,0x79,0xde,0x0f,0xaa,0xff,0x31,0x96,0x97,0xb6,0x7d,0xad,0xc9,0xcc,0xb5,0xae,0x0d,0x6e,0xb7,0xb5, -0x6c,0x6c,0x29,0x61,0xca,0xa5,0x45,0x33,0x7e,0xe3,0xd4,0x38,0xc9,0x87,0x6a,0xec,0x58,0xb0,0x6a,0x81, -0xfa,0x06,0xd2,0x80,0x7e,0x23,0x2c,0xa7,0xea,0xe3,0xed,0x4a,0xcb,0xbc,0xd5,0x02,0x94,0x53,0xbb,0xc6, -0x7b,0x41,0x24,0x85,0xad,0xf2,0x4e,0x71,0x0e,0x1a,0x2d,0x0f,0x2d,0xd4,0x64,0x74,0x00,0xf7,0x3d,0xc4, -0x1d,0xf7,0xba,0x28,0xeb,0x96,0x39,0xb2,0x41,0xda,0xd5,0x22,0x5b,0x1a,0x31,0xcc,0x0c,0x68,0x4b,0x15, -0x57,0xad,0x4c,0xd0,0x96,0xe5,0x70,0x59,0xa5,0xab,0x79,0xc1,0x21,0xe9,0xe7,0x69,0xde,0xb3,0x8c,0x76, -0xdb,0x29,0x19,0xc3,0x12,0xb0,0x2b,0xb2,0x16,0xfa,0xde,0xf5,0x65,0xb3,0x8b,0x80,0x07,0x1c,0xbc,0x86, -0x61,0xb9,0xa0,0x03,0x90,0x5b,0x81,0x6e,0xbc,0x05,0xcb,0x4d,0xca,0xb1,0x05,0x44,0xc3,0xeb,0x8b,0xd2, -0xf6,0x9c,0x04,0x61,0xd6,0xe7,0x1e,0x56,0x06,0xfd,0xf8,0xe2,0xf9,0xd3,0xba,0x5e,0xaa,0x0d,0x4f,0xd1, -0xe8,0x1a,0x58,0xce,0x7c,0x78,0xfe,0xa5,0x8e,0x6f,0x46,0xec,0x0e,0x7a,0x78,0xef,0xde,0x67,0x74,0xf1, -0xf9,0x26,0xfc,0xa3,0x8e,0x7b,0x4a,0xf1,0xe1,0x28,0x4d,0xd3,0xa7,0xac,0xe2,0xdd,0xdd,0x3f,0x60,0x2d, -0x78,0x45,0x1d,0xfb,0x90,0x0e,0xc2,0x54,0xcd,0x2c,0x59,0x54,0xd0,0x48,0xfe,0x51,0x43,0x25,0x89,0x4f, -0x63,0xca,0x05,0xe9,0x74,0x85,0x0d,0xbd,0x77,0xa6,0xb6,0x52,0xc9,0x60,0xb3,0x54,0x99,0xaf,0xd7,0xc8, -0x1b,0xd1,0xca,0xad,0x33,0x83,0x12,0x79,0x57,0x0e,0x70,0x3c,0x03,0x5b,0x31,0x20,0x71,0x58,0xd1,0xc4, -0x96,0x2a,0x72,0xd4,0x52,0x40,0x05,0xfb,0xb5,0x0a,0x50,0xc6,0x47,0x89,0x5a,0x36,0x40,0xdc,0x11,0x3d, -0x10,0xc5,0x09,0x4d,0xa7,0xaa,0xba,0x2a,0xca,0x39,0xe8,0x01,0x7d,0x2d,0x52,0x47,0x09,0x18,0x21,0x01, -0x0f,0x9a,0x87,0x15,0x3c,0x9f,0xac,0x07,0x74,0x3b,0xae,0xcd,0x69,0x12,0x91,0x16,0xdb,0x27,0xd1,0xbe, -0x67,0x7e,0xf3,0x09,0xca,0xb4,0x5a,0xb8,0x5e,0x67,0x53,0xef,0xc7,0x7d,0x35,0x4a,0xc4,0x18,0x32,0x3c, -0x34,0x7c,0x0d,0x7b,0x9f,0xc7,0x9e,0x3b,0xac,0x9e,0x70,0x3a,0x5c,0xed,0x2c,0xa8,0xba,0x1c,0x4e,0x12, -0x32,0xea,0xf3,0xb8,0x6f,0x5a,0xef,0x58,0xd3,0x27,0x67,0x49,0x4b,0x19,0x43,0xcd,0x8d,0x18,0x78,0x7c, -0xc1,0xfc,0x08,0x5f,0x31,0x53,0xc0,0x57,0xcc,0x88,0xb0,0xd0,0x4b,0xf4,0xf2,0x6c,0x9b,0x11,0x2a,0x76, -0x87,0xe3,0x22,0x54,0x9a,0x13,0x8a,0x94,0xb0,0x8b,0x9f,0x76,0xd0,0x50,0x2a,0x75,0x9a,0x9e,0x14,0x74, -0xd6,0x55,0x29,0x83,0xa8,0xf0,0xf5,0xf3,0xb0,0xb2,0x44,0x61,0x78,0xf1,0x4b,0x3d,0xd5,0x8f,0x66,0x30, -0xd4,0xe9,0x49,0x26,0xb2,0x5b,0xc6,0x0a,0xe4,0x00,0xa6,0x22,0x2c,0x96,0x93,0x0a,0xbf,0x09,0x7a,0x14, -0xaa,0x56,0x4a,0xc4,0xf0,0xbc,0x39,0xc9,0xf2,0xa4,0x7c,0x1f,0x35,0x8f,0x37,0xd1,0x0d,0x0b,0x79,0xdd, -0x84,0x1b,0x2a,0xb9,0x57,0x40,0xe2,0x0b,0x2e,0xa6,0xe9,0x49,0xc4,0xee,0x2a,0xad,0xfe,0xcc,0x7d,0xdd, -0xda,0xc6,0xa5,0xcb,0xf4,0xf1,0xa4,0xe9,0xed,0x32,0xea,0xed,0x6f,0x6b,0xd0,0x3e,0x67,0x88,0xe3,0x86, -0x35,0x64,0x84,0xd5,0x5e,0xb6,0x2e,0x07,0xc2,0x85,0x04,0x8e,0x40,0xf9,0x32,0x5a,0xc2,0xcd,0x55,0xc2, -0xc8,0xd5,0xce,0x81,0xa1,0x66,0xa6,0x5b,0x70,0x2e,0x34,0x7f,0xb7,0x52,0xa8,0x94,0xc2,0xdf,0xad,0x36, -0x1d,0xb9,0x06,0x17,0xc3,0x21,0xc9,0x36,0x86,0xe3,0x69,0x80,0xea,0xed,0xf9,0x97,0xda,0x4b,0x80,0xbd, -0x3d,0xf5,0xee,0x34,0x14,0x6e,0x04,0x86,0x63,0x4d,0x26,0x4a,0x96,0x67,0x34,0x1b,0x92,0x46,0xa9,0x30, -0x1a,0xfd,0x43,0xb8,0xe3,0xa8,0x28,0xb6,0x3c,0x4f,0x4f,0x2f,0x7b,0x9f,0x5f,0xef,0x37,0x6f,0x1c,0x4d, -0x86,0x2a,0xed,0xe0,0xf8,0xc4,0x9f,0x44,0xc8,0x75,0x8d,0x84,0x81,0x3c,0x66,0xf5,0x85,0xa3,0x73,0x60, -0xed,0x81,0xca,0x66,0xcb,0xde,0x2f,0x7c,0xd5,0x63,0xe8,0x03,0x89,0x1e,0xa4,0xfd,0xfd,0x65,0xf8,0x32, -0x67,0x0f,0x6e,0x22,0x29,0x32,0xbb,0x26,0x7d,0xc7,0x07,0x5c,0xea,0xb1,0xb0,0xdb,0xaf,0xe2,0x58,0x0e, -0x8e,0xcf,0xea,0xcf,0x86,0x24,0xf7,0x16,0x02,0xe1,0x97,0x2b,0xb9,0x51,0x86,0xd2,0xe3,0x5e,0x72,0xcc, -0xfc,0x30,0x33,0x1b,0x9e,0x8a,0x6a,0x74,0x9f,0x36,0x67,0xd6,0xea,0xde,0x28,0xdd,0x14,0x9c,0x62,0xf9, -0xcd,0x43,0xb9,0x0f,0xab,0xf2,0x94,0x9e,0x11,0x81,0x26,0xee,0x89,0xb2,0xf0,0xb0,0x50,0x76,0x94,0x68, -0xdc,0x25,0x55,0x26,0xd0,0x8c,0x36,0x57,0x44,0xe8,0xbc,0xcc,0xb7,0x48,0x8b,0x88,0xec,0x3f,0x1f,0x7d, -0xce,0xbb,0x99,0x8a,0x95,0x46,0x8d,0xcd,0x53,0x3e,0xdb,0x39,0x1e,0xff,0x35,0xb8,0xc0,0xdb,0x26,0xae, -0xd2,0x80,0xfe,0x58,0xc3,0x58,0xe0,0x3b,0xe8,0x3c,0xe3,0xe0,0x78,0xe2,0x4f,0xe2,0xbd,0xf5,0x9d,0x60, -0x7d,0x3c,0x51,0x76,0x1b,0xd6,0xac,0xc4,0x61,0x64,0x19,0x79,0xa7,0x4a,0x18,0x2c,0x6a,0xa9,0xa5,0x96, -0x0d,0x77,0x11,0x0e,0x7f,0xac,0xc5,0x3e,0x4e,0xa4,0xe1,0x62,0x59,0x3a,0xf0,0x7e,0x11,0x49,0x83,0xc3, -0x31,0xa7,0x08,0x0b,0x89,0xe9,0xd1,0x37,0x3b,0x50,0x0a,0xeb,0xae,0x96,0xd6,0xe0,0xf5,0x80,0xef,0xd6, -0x43,0x4e,0xa4,0x81,0x63,0xbe,0xd3,0x7a,0x6e,0x74,0x7e,0x30,0xf1,0xe8,0x2f,0x1d,0xa0,0xdb,0x86,0xfc, -0xb5,0x92,0x22,0xb0,0xc8,0xa7,0xfe,0xef,0x8a,0x7c,0x9a,0x32,0x59,0x24,0x43,0x0c,0x04,0x7e,0xc5,0xbd, -0x0b,0x8a,0x25,0x69,0x05,0x03,0xd2,0xdb,0x47,0x7d,0x7d,0x8a,0xcd,0x74,0x1b,0x74,0x9f,0xb6,0xcd,0x35, -0xdc,0xb7,0xb0,0x39,0x76,0x1e,0xc0,0x94,0xc3,0x7d,0x12,0x56,0x13,0xda,0x4b,0x20,0x10,0xaf,0x66,0x46, -0x1a,0xf4,0x9d,0x48,0x83,0x06,0x99,0x49,0xae,0xfb,0x8c,0xfb,0xca,0x12,0x3a,0xe9,0xbe,0xd3,0x72,0x22, -0x95,0x9c,0x8d,0x41,0x32,0xde,0xdf,0x0d,0x3d,0x98,0xaa,0x05,0x26,0x5a,0xc6,0x99,0x4d,0xbc,0xb5,0xb5, -0x99,0x65,0x42,0x93,0x0d,0xbc,0x9d,0xab,0xa4,0xda,0x21,0x26,0x77,0x07,0xf3,0x89,0xf5,0x5d,0x09,0x75, -0xc5,0x26,0x74,0xbb,0x26,0x96,0x23,0x30,0xdc,0x16,0xa6,0xd9,0x8c,0xe3,0xa7,0xd9,0x59,0x27,0x4d,0x40, -0xf7,0x4d,0x58,0x6a,0x01,0xb6,0x3d,0x13,0x35,0x19,0x29,0x26,0x62,0xc3,0xde,0xb8,0x50,0xfb,0xd4,0x7e, -0xce,0xaf,0x08,0x6b,0x09,0x74,0xdd,0xee,0xfd,0xbc,0xd5,0x99,0x98,0xd0,0xb0,0xa4,0xcd,0x02,0x06,0x96, -0x76,0x07,0xa7,0xa0,0xe1,0x2e,0xfc,0x84,0x0f,0x5f,0x49,0x5c,0x68,0x73,0xa3,0xc0,0x1c,0xc5,0xc5,0xcc, -0x4d,0xa4,0xc2,0x08,0x91,0xa0,0xcf,0x79,0x1d,0x7c,0x17,0x08,0x8f,0x33,0x08,0x51,0xf0,0x96,0x67,0x5c, -0xcf,0x57,0x3e,0x66,0x27,0x8e,0x07,0x0d,0xc8,0x80,0x15,0x7c,0xe1,0x08,0x93,0xf3,0xfe,0xd1,0x81,0xfc, -0xd8,0x37,0x5e,0x78,0x4f,0x88,0xaa,0x39,0x28,0x28,0xc6,0x7b,0x23,0xb6,0xa5,0xac,0x05,0xe6,0x4c,0xda, -0x02,0x0a,0xcb,0x93,0xad,0x81,0xc8,0x52,0x53,0x77,0x3a,0x1b,0xf7,0x3a,0xeb,0x29,0x9d,0x16,0x51,0xec, -0xb1,0xf1,0x22,0x37,0x2b,0x9f,0x58,0xbf,0xde,0x0e,0x81,0x97,0xcf,0xc7,0x76,0x01,0x02,0xd7,0xb4,0x25, -0xed,0x27,0x49,0x95,0x32,0xd4,0x1b,0xcb,0xd6,0xf3,0xc6,0x36,0x4d,0xd9,0x2f,0x74,0x89,0x65,0x19,0xd0, -0x52,0xa0,0x94,0x90,0x48,0x3d,0x36,0x11,0x6a,0x68,0xd2,0x01,0x43,0x0f,0xb6,0x54,0x93,0x69,0xbb,0x14, -0x80,0xa1,0x07,0xb3,0xc8,0xcf,0xe2,0x13,0x9f,0xe8,0x17,0x75,0x11,0xb0,0x9d,0x11,0xda,0x5c,0x63,0x52, -0x9f,0x03,0x38,0xbb,0xa1,0xe9,0x30,0x74,0x49,0x4b,0x7a,0x88,0xfc,0xec,0x73,0x9a,0x91,0x32,0x30,0x0f, -0xb5,0xd5,0xf9,0x1e,0x00,0x07,0x38,0x49,0x22,0xd2,0x9c,0xe5,0xae,0x69,0x8e,0xa5,0x95,0x38,0x02,0x94, -0xf1,0xf7,0xf0,0x22,0x61,0x91,0x32,0xce,0xe8,0x38,0xd2,0xcb,0xdd,0x28,0xc4,0x7d,0xc7,0x00,0xcc,0x55, -0x3b,0x46,0x75,0x0f,0xd0,0xa0,0x00,0x87,0x7b,0xaf,0x5e,0xbe,0x79,0xdb,0x8a,0xe7,0xd6,0x27,0x75,0xc9, -0x88,0xd0,0xb5,0x04,0x2f,0x62,0x7c,0xc1,0xf2,0x9e,0x9a,0xf6,0x41,0x16,0x0b,0xda,0x5b,0x5f,0xd1,0x2c, -0x63,0xca,0x1e,0xa9,0xfd,0x72,0xc2,0xdb,0xec,0x3c,0x7b,0x87,0x3d,0x56,0x9d,0xd7,0xed,0xf9,0x09,0x5b, -0x24,0x09,0x36,0x5f,0xca,0xd9,0x5a,0xaf,0x7e,0x1a,0x32,0x57,0xb2,0x95,0x74,0xce,0xcf,0x0e,0xfc,0x54, -0xb1,0x5e,0x4f,0x53,0x87,0xe1,0x45,0xa0,0xc6,0x19,0x78,0x48,0x2d,0xe2,0x68,0x04,0x68,0x8d,0x6e,0x22, -0x6c,0x34,0xba,0x61,0x4b,0x21,0x6c,0xab,0x96,0x1d,0xa5,0x73,0xd8,0x88,0x30,0x7b,0xa0,0xd2,0xdb,0x96, -0xba,0xae,0x64,0x80,0x37,0xbd,0x26,0x88,0x8f,0x7d,0x10,0x57,0x60,0x52,0xf3,0x2d,0x72,0xb1,0x73,0x22, -0xfc,0xec,0x27,0x26,0x68,0x67,0xf6,0xe1,0xd4,0xc4,0xa2,0xc2,0x96,0x04,0x9b,0xb4,0x8d,0x3e,0x87,0x73, -0xa3,0xe5,0xcc,0xce,0x96,0xae,0x2f,0xf9,0xf2,0xf6,0x18,0x88,0xa2,0x9f,0xb6,0xc0,0xcf,0x75,0x54,0x0c, -0x4f,0xfc,0x2b,0xb0,0xa6,0x18,0x99,0xd4,0x03,0x9b,0x9f,0x9d,0x62,0x27,0x3c,0x6d,0xf0,0xcd,0x87,0x3a, -0x79,0xec,0xe9,0xa8,0x34,0x1c,0x6d,0xe5,0x4c,0xd5,0xc3,0x57,0xf0,0x84,0x2a,0x73,0xd6,0xa5,0xab,0x30, -0x8b,0xf2,0x64,0xc1,0xf8,0xe4,0xe1,0x22,0xf6,0x9b,0x28,0x1c,0x28,0x02,0xb8,0x4d,0xd9,0x35,0xe3,0xe6, -0xc4,0xa7,0x01,0x2b,0x56,0x56,0xf6,0xd6,0x0e,0x30,0x5c,0xf8,0xd1,0xc0,0x54,0xa3,0xa4,0xe2,0x74,0x3d, -0x7c,0x06,0x79,0xe7,0x70,0x34,0x59,0x5c,0x32,0x2c,0x79,0x10,0xc1,0x39,0xa2,0x41,0x47,0x2f,0x88,0xbb, -0x81,0x33,0xaf,0xf5,0x68,0x85,0x47,0xdd,0x85,0xc6,0x46,0x10,0xb5,0x88,0x84,0x52,0x76,0xe6,0xb4,0xd0, -0x13,0xe1,0x37,0xae,0x70,0x2c,0x39,0xfc,0x0d,0x25,0x5e,0xe2,0x57,0xee,0xf6,0x81,0x2d,0xb0,0x1c,0x24, -0x4d,0x12,0x54,0x85,0xd3,0xe0,0x42,0xdd,0xef,0x57,0xfc,0x83,0x8d,0xd9,0x83,0x55,0xf4,0x39,0xfb,0x39, -0x4e,0x20,0x0f,0x00,0xdc,0xb5,0x2a,0x78,0x19,0x44,0x67,0xdc,0x5f,0x4b,0x85,0x59,0x6b,0x07,0x79,0x6d, -0x8f,0x31,0x13,0xfd,0x6d,0x8e,0xec,0x56,0x80,0x40,0x4c,0xd0,0x3e,0xf1,0x9c,0xcc,0x6b,0xc9,0x76,0x68, -0x26,0x91,0x1d,0xbb,0x6c,0xec,0x38,0xe8,0xb7,0xfd,0x6a,0x8b,0x49,0xb1,0x4d,0x4e,0x84,0x91,0x2a,0xb6, -0x21,0xc8,0x33,0xfc,0x9e,0x1b,0x70,0x13,0x82,0xc1,0xb9,0xba,0x51,0x34,0x9c,0x51,0xcf,0x2d,0x9f,0x98, -0xf0,0x06,0x78,0x92,0x3c,0xde,0x83,0x6c,0xc8,0x61,0x9f,0xa5,0xc2,0xfb,0xb4,0xfb,0x70,0xee,0x6f,0x69, -0x26,0x70,0x7c,0x9c,0x52,0x75,0x35,0xa7,0xfa,0xb1,0x95,0xea,0x39,0xc3,0xd7,0x47,0x9c,0xdb,0x48,0xd2, -0x8f,0x36,0xda,0x21,0x34,0x5c,0xf6,0x84,0xc0,0x81,0x13,0xa3,0x12,0xdc,0x6a,0x88,0xb7,0xd0,0xf8,0x31, -0xd0,0x16,0xe7,0x66,0xa5,0xbd,0xe3,0xcd,0x9c,0x56,0x2b,0x20,0xb7,0x17,0xdc,0x84,0xf6,0xb3,0x6d,0xdd, -0x13,0xf9,0x3a,0x9c,0x37,0x57,0xfc,0x95,0xc8,0x1c,0xd1,0x6b,0xd6,0x53,0x44,0xce,0xf1,0x53,0x94,0x2f, -0xe4,0x1b,0x3e,0x49,0x88,0xb0,0xab,0xdf,0x06,0xba,0x5e,0xd2,0x61,0x7a,0x15,0xf2,0x07,0x82,0xc9,0x4f, -0xbd,0x25,0xa0,0xfc,0x6c,0x3d,0x6e,0xf7,0x5b,0x4f,0x62,0x74,0x5a,0x93,0x9a,0x88,0x1c,0xe7,0x2d,0xd3, -0x9f,0x4b,0xd8,0x6f,0x5a,0x29,0x71,0x00,0xde,0x82,0xf2,0x9a,0x9c,0xd5,0x1a,0x90,0x02,0x3a,0x69,0x39, -0x72,0x81,0x78,0x7b,0x6c,0x42,0xbb,0xd5,0x1f,0x69,0xc2,0xeb,0x0a,0xcf,0x9d,0x7e,0x1b,0xa7,0xac,0x44, -0xd7,0xf4,0xac,0x8f,0xf8,0x89,0x60,0xdd,0xf9,0x48,0x13,0xde,0xf5,0xfa,0xef,0xe9,0xa6,0x85,0x6d,0x68, -0x00,0xaa,0x23,0xcf,0x9a,0x5e,0x5e,0x68,0xf0,0xac,0xe5,0xb9,0x9a,0x9c,0x5b,0x9c,0x1d,0x9c,0x24,0x20, -0xef,0x0a,0xb0,0xd1,0xc6,0x25,0x2c,0x3b,0x08,0x44,0x56,0x4e,0x8d,0x9b,0xe4,0xd8,0x96,0xe5,0x2b,0xe7, -0xa5,0x34,0x98,0x10,0x4b,0x1e,0x7d,0xd5,0x8e,0x92,0x08,0xf7,0x62,0x6b,0x49,0xd9,0x11,0x4a,0x26,0xb4, -0x9a,0xe1,0x7d,0x07,0x04,0x66,0x5e,0x0d,0x3e,0x96,0xb7,0x6e,0x94,0x9f,0xd3,0x8d,0xd5,0xdc,0x28,0x0b, -0xf3,0x49,0x16,0x15,0xf6,0x3a,0x0c,0xf8,0xdb,0x38,0xe3,0x48,0x02,0x65,0x4f,0x1c,0xbe,0x16,0xa8,0x25, -0x76,0x66,0xde,0x13,0x3e,0x10,0x97,0x84,0xe3,0x63,0x38,0xf1,0xa9,0xec,0xf4,0xb9,0x13,0xa3,0x44,0x05, -0x45,0xaa,0x69,0x63,0x52,0x87,0x24,0x36,0x62,0xc6,0xd1,0xa2,0xd9,0x36,0x28,0x53,0x0e,0x5e,0x11,0xe5, -0x9b,0xc0,0x1e,0x5a,0x15,0xb8,0xc8,0x84,0x4d,0xe1,0x09,0x1f,0xa9,0xe0,0x29,0x7d,0x91,0xc5,0xf9,0x2b, -0x13,0xec,0x82,0x19,0x7c,0x6f,0x90,0x6a,0x91,0x4d,0x04,0x93,0x86,0xc8,0x2b,0x56,0x35,0x3f,0xde,0xb4, -0xc0,0x08,0x65,0xc0,0x4b,0x6b,0xc0,0x1b,0x79,0x72,0xdc,0xee,0x3c,0xf0,0xea,0x16,0x56,0xa7,0xe1,0xf0, -0x33,0x8e,0x77,0xc6,0x98,0x71,0x02,0xa8,0x5c,0xf0,0xef,0x44,0x2d,0x2c,0x2a,0x5e,0xd6,0x6f,0xc3,0x88, -0x76,0xe6,0x12,0xc8,0xfb,0x6d,0x73,0x89,0x98,0x50,0x4c,0x10,0x0b,0x85,0x44,0x5a,0x44,0x34,0x6c,0x6a, -0xda,0x3c,0x8b,0x1a,0xfa,0xdd,0x26,0xe4,0x53,0x4f,0x08,0x2f,0x27,0xfb,0xca,0x09,0x02,0x89,0xe8,0x36, -0x5d,0xc2,0xcf,0xe0,0xea,0x97,0xc4,0xb7,0xd6,0x7c,0x84,0xe2,0xb3,0x2b,0xcd,0x42,0x7c,0x1f,0x16,0xce, -0x9d,0x4e,0x20,0x8b,0x57,0x27,0x70,0xef,0x9a,0xc2,0x8d,0xdf,0x3f,0xcf,0x77,0x45,0x0a,0xd0,0xfc,0x2a, -0x68,0x10,0xec,0xb9,0x3b,0x00,0x8d,0x02,0x94,0x2f,0x9a,0xe2,0xda,0xf4,0x94,0x11,0x20,0xdb,0xae,0x55, -0x70,0xaa,0xdc,0x8a,0xcc,0xa6,0xd8,0xc2,0x54,0x79,0xdf,0xd1,0x2b,0xe8,0x97,0x3a,0x9f,0xb4,0x3e,0x38, -0x3b,0x33,0x5f,0x04,0x9b,0x50,0x7b,0xa1,0x7e,0x00,0x90,0x5a,0xb8,0x4f,0x05,0x2c,0x0d,0x20,0xc2,0xde, -0xaf,0xcc,0x37,0xc0,0xb3,0xe8,0x80,0x62,0x58,0xc5,0x7b,0x77,0xef,0x7a,0x4a,0xa1,0x87,0x07,0x94,0x35, -0x8c,0xad,0xee,0x7a,0x61,0xae,0x17,0xf1,0x45,0xb1,0x98,0xbf,0x86,0xbc,0xd7,0x61,0x6a,0x53,0xc1,0xa1, -0xa3,0xc7,0x3f,0x24,0x59,0x3d,0x18,0x44,0xfa,0x96,0x61,0xa5,0x85,0xe7,0x62,0xd7,0x82,0xd8,0x71,0x34, -0x30,0x07,0x5b,0x68,0xde,0x63,0xcb,0x02,0xfa,0xbc,0xc1,0xe1,0x8a,0xb3,0xb0,0x09,0xbe,0x6e,0x8e,0x3e, -0x82,0xb8,0xb8,0xb7,0x27,0xbf,0xc3,0xe4,0x72,0xae,0xaf,0x7d,0x4f,0x2c,0x28,0x81,0xf9,0xdc,0x13,0xdd, -0xe6,0x3c,0x55,0xcc,0xcd,0xf7,0xf0,0x8e,0xfa,0xf5,0x9f,0x48,0x1a,0x7e,0x83,0xeb,0x3b,0xd6,0x1a,0xc8, -0x8b,0x87,0x45,0x7e,0x46,0xc7,0x33,0x37,0x6c,0xa4,0x39,0xd2,0xdf,0xe1,0x1d,0x85,0x59,0xe4,0x3b,0xf1, -0x37,0xb5,0xa0,0x4f,0xab,0xdc,0x9a,0x57,0xea,0xfe,0xfb,0x1a,0x3d,0xb7,0x01,0x18,0x4b,0xf3,0x10,0x1f, -0x9e,0x33,0x24,0xeb,0x26,0x38,0x3a,0x50,0x52,0x4b,0x2d,0xbd,0xec,0x38,0x95,0x84,0x19,0x73,0x1e,0xd3, -0x99,0x9c,0x19,0xc7,0x62,0xdd,0x76,0x67,0x78,0x02,0x9d,0x78,0x5a,0x32,0x0f,0x9b,0x27,0xef,0x32,0x1a, -0xfb,0xa2,0x64,0x45,0xd3,0x83,0x73,0xf6,0x32,0xf3,0xbc,0x50,0x0a,0x1c,0xae,0x12,0x36,0xd7,0xe9,0x20, -0x70,0x67,0x66,0xcf,0x8b,0x5b,0x46,0x8f,0xc4,0x87,0x1d,0xf8,0xa7,0x17,0x65,0x71,0x99,0x06,0xd3,0x9d, -0xe3,0x83,0x99,0x3f,0x3d,0xbe,0x1a,0xce,0x06,0xc1,0x41,0x13,0x2b,0xf6,0xc0,0xbf,0xe2,0xd8,0x77,0xb7, -0x24,0x40,0xdc,0xae,0x24,0x60,0x6f,0xf1,0x77,0x74,0xce,0xa1,0xa2,0x83,0xc9,0xf6,0xd4,0x97,0x55,0x96, -0x06,0x3b,0x3d,0xaf,0xac,0xd3,0x35,0x4c,0x59,0x68,0x5f,0x07,0xf0,0x17,0xfb,0xca,0xd3,0x57,0xc5,0x1f, -0xd9,0x62,0xa1,0x4a,0x99,0xec,0x94,0xef,0x22,0x9d,0x43,0x30,0xb1,0xf2,0xa0,0x19,0x71,0xa3,0xba,0x2c, -0x82,0xa0,0x80,0xfb,0x47,0x55,0x8a,0x1e,0x20,0x32,0x90,0x37,0x02,0x72,0x70,0x16,0xbb,0xbd,0x06,0x8b, -0x48,0xf5,0x44,0x7d,0x0f,0x43,0xda,0xcc,0xea,0x7f,0xf7,0xed,0xd4,0xbc,0x62,0x09,0xaa,0xfb,0x72,0xa8, -0x4a,0x04,0x8c,0x89,0xea,0x90,0x76,0x0a,0xe9,0xd4,0x4e,0xb6,0xc3,0x2a,0x39,0x4b,0xca,0x0c,0xe8,0x14, -0x90,0x20,0xd8,0x8c,0x90,0xb6,0xb6,0x07,0xbe,0xb7,0xd1,0x6e,0xd2,0xa9,0x7d,0x2c,0xec,0x3f,0x10,0xae, -0xef,0xf8,0xbc,0x69,0xdc,0xb1,0xd1,0xe1,0x35,0x53,0x00,0x5d,0xfe,0xd8,0x78,0x6f,0x55,0x41,0x12,0x57, -0xec,0xbb,0x75,0xc1,0x51,0x7c,0x63,0x2b,0x1b,0x16,0x03,0x8a,0x52,0x1b,0x57,0xdf,0x6a,0x4f,0x30,0x05, -0xa4,0x03,0x2d,0xfa,0x43,0x05,0x80,0x01,0x8d,0xe1,0xa3,0xec,0x5d,0xa5,0xa3,0xf3,0x24,0x35,0x42,0xa7, -0xb3,0x13,0xa3,0x79,0xa6,0x5c,0xa0,0x70,0xbc,0x17,0xa4,0x3c,0x39,0xdf,0x89,0xd2,0x3c,0x59,0x9c,0xb2, -0x13,0xe8,0x23,0x3a,0x21,0xb3,0x9b,0x0e,0x7d,0xb6,0x31,0x8b,0xb0,0x09,0xb2,0xd1,0x93,0xb0,0x47,0xd0, -0xa9,0x10,0xa8,0xe0,0x2d,0x2c,0x6e,0xca,0x4e,0xa8,0x1a,0x3a,0x86,0xbd,0x7f,0xcd,0x2f,0xfd,0xc6,0xf1, -0xdd,0xfa,0x04,0x9a,0xa9,0x84,0xe8,0x4b,0xb9,0xf5,0xab,0x53,0x9d,0x42,0x7f,0x88,0xd8,0x1f,0x59,0x62, -0x98,0x17,0x40,0x2e,0xdb,0xb5,0xce,0xaa,0x47,0xca,0xff,0x6b,0x5b,0x65,0xb9,0xbf,0x5b,0x9e,0x62,0x6e, -0x1e,0x7d,0xdd,0x7d,0x6b,0x6e,0xf8,0x40,0xe4,0x37,0x3b,0x0c,0x00,0x15,0x7f,0xea,0x49,0x38,0x1f,0x53, -0x7b,0x46,0x7f,0x1a,0x78,0x9f,0xee,0x1c,0xdc,0xd7,0x0d,0x31,0xef,0xe2,0x26,0xa3,0xa5,0x39,0x9d,0xa8, -0xdd,0xe2,0x79,0x72,0x92,0x2e,0x68,0x92,0x79,0x47,0x0b,0x5c,0xb5,0xb2,0xe7,0x67,0xc4,0x2e,0xea,0xdc, -0xef,0x1f,0xe7,0x3b,0x3b,0x47,0xd5,0x32,0xc9,0xef,0xab,0x14,0x54,0x69,0xf1,0x6b,0xe3,0x8c,0x06,0x1e, -0x51,0x45,0xbc,0x3d,0xce,0x8f,0x0e,0xf8,0xe3,0x46,0xde,0x44,0x5c,0xa9,0x5b,0xad,0xa6,0x12,0x80,0x0d, -0x8c,0x9d,0x1a,0x89,0x48,0x8f,0xea,0xea,0x7b,0xc8,0x4f,0x37,0xa9,0xc8,0x3f,0xa6,0xbe,0xf9,0xf6,0xea, -0xfe,0xb7,0x2b,0x9b,0x0b,0x9a,0x21,0xd7,0xc0,0x1a,0x8e,0xec,0xd5,0x45,0x91,0xa7,0x3c,0xa6,0x92,0xe0, -0x65,0xfe,0xe9,0xd1,0x81,0x23,0x6f,0xbb,0xa5,0xfd,0x1f,0x9b,0xe7,0xd9,0xd9,0x47,0x67,0x9a,0x5b,0x7d, -0x9a,0xdf,0xd6,0xa5,0xb2,0x6a,0xda,0x65,0xab,0xee,0x92,0x97,0xa6,0x3b,0x3f,0xb2,0x70,0xf5,0x15,0xfb, -0xa8,0xdf,0x9e,0x31,0x27,0xf9,0x50,0xf6,0x92,0xd6,0xc9,0x5b,0x02,0x13,0xdf,0x96,0x35,0xa7,0xf8,0xd8, -0x9c,0x11,0xc0,0xd4,0x5e,0x9f,0x7d,0xe4,0x2d,0x76,0x25,0x0c,0x66,0x17,0x1f,0xf2,0xde,0xa7,0x56,0xec, -0x1d,0x7f,0x6a,0x65,0xec,0x2e,0x32,0x67,0x06,0xb7,0x56,0xe8,0x2c,0x50,0x20,0x86,0xab,0x5c,0xbc,0x94, -0x19,0x1f,0x33,0xf4,0xc4,0x5e,0xd1,0xae,0xda,0x2f,0xe7,0x69,0x6d,0xe8,0xa5,0x2d,0xdf,0x76,0x63,0x05, -0xec,0xd2,0x86,0x41,0x8c,0x6f,0x72,0x5a,0xaf,0x92,0xc5,0x24,0x55,0x17,0x5a,0x49,0xd3,0xa6,0x69,0x6d, -0xaa,0xd8,0x65,0x37,0x98,0x8b,0xc5,0xc6,0xa4,0xd5,0x4f,0xee,0xd4,0x62,0xc9,0xb1,0x9e,0x56,0x95,0xbc, -0x73,0x6a,0x0a,0x60,0x12,0x39,0x98,0xd1,0xfb,0x41,0x6c,0xc0,0x5d,0x13,0x89,0xc8,0xa2,0x0e,0x65,0xfb, -0x4a,0xe6,0x78,0xc8,0x1e,0x3b,0x2e,0x41,0x70,0x8a,0xa8,0xfb,0x8a,0xc8,0x9b,0x22,0x6a,0xab,0x88,0xdc, -0x2d,0xa2,0xe4,0xc3,0xa2,0x94,0x61,0x11,0x7f,0x96,0xbc,0xd1,0xb1,0xac,0xba,0x5f,0x4f,0x2a,0x3a,0x0a, -0x66,0x83,0xbe,0x22,0xec,0xc1,0xd5,0x85,0xd9,0xb3,0x4e,0xc2,0x41,0xb6,0x06,0x97,0xcb,0xbf,0x91,0x10, -0xd1,0x19,0x90,0xd7,0xac,0x62,0x3a,0x8b,0xc1,0x49,0x3c,0xf8,0x7c,0xe3,0x4c,0x7b,0xf7,0xe5,0x5f,0x37, -0x41,0x7b,0x1c,0xf3,0x17,0x80,0x83,0x40,0x28,0x07,0xeb,0x98,0x6a,0x39,0xa7,0x64,0x1d,0xfc,0x96,0x70, -0x57,0x36,0x3d,0xb3,0xab,0xf9,0x0d,0x78,0x67,0xac,0x24,0x72,0xeb,0x75,0x36,0x2c,0xa8,0xdf,0xb2,0x1c, -0xd6,0x07,0x38,0x32,0x8a,0x4d,0x09,0xad,0xa3,0x15,0x11,0x54,0x65,0x45,0x49,0x09,0x61,0x48,0xb0,0x2a, -0xb1,0xc3,0x2c,0xde,0x3f,0x04,0x92,0x07,0xe2,0x77,0xd9,0x7d,0x46,0x4b,0xab,0x4c,0xce,0x59,0xe4,0xaf, -0xf7,0xd7,0x18,0x50,0x11,0xf2,0x1a,0x52,0x1a,0x91,0x4d,0x34,0xa3,0xd7,0x6e,0xbd,0xd7,0x4c,0x91,0xf5, -0x7a,0xd4,0x6e,0xfe,0x23,0xca,0xfd,0x45,0xf1,0x2e,0xb5,0x0f,0xe9,0x0d,0x5f,0x35,0x16,0x0b,0x85,0x4e, -0x0d,0x63,0xbb,0x8e,0xba,0xf5,0x55,0xec,0xd7,0x83,0x6e,0xcd,0xf6,0x7b,0x9a,0x10,0x1c,0x08,0xc7,0x81, -0x99,0xf5,0x26,0x9b,0xa7,0x61,0xc5,0x5e,0x7a,0x55,0x4c,0x53,0xac,0xba,0x7f,0xc8,0x97,0x87,0x98,0xd1, -0xd5,0xdd,0x56,0xc2,0xce,0xd8,0xb2,0xf4,0x2d,0xdf,0xb8,0xdb,0x9d,0x3d,0xec,0xb9,0x43,0xe4,0x92,0x79, -0xb6,0xaa,0x36,0xee,0x46,0x2a,0xa9,0xad,0x10,0xed,0xd1,0xbe,0x95,0x61,0x3b,0x05,0x4b,0xc6,0xf6,0xfd, -0xc3,0xfd,0x2a,0x68,0x55,0x6e,0xd3,0x99,0x5c,0xe8,0xdd,0xc7,0xf9,0xbc,0xaf,0x73,0x3f,0xaa,0x6b,0x61, -0xa6,0xb7,0x6d,0xb2,0x49,0xb7,0x52,0x85,0xce,0xa1,0x43,0xf3,0x3f,0xae,0x9f,0x2d,0xbe,0x06,0x2a,0x68, -0x4f,0xed,0xee,0x74,0xf0,0xbd,0x1f,0x0f,0xbf,0x08,0xd4,0x34,0x05,0xb8,0xe3,0xd6,0x94,0xbb,0xdb,0xde, -0x04,0xcd,0xe7,0xbd,0xd3,0x5a,0x6c,0x4a,0x4c,0xad,0x95,0x3d,0x5b,0xf7,0xcc,0xab,0xfa,0xfd,0x21,0xe7, -0xa5,0xb9,0x50,0x75,0xdb,0x8e,0xae,0xd8,0x5b,0x0d,0xcd,0x71,0xcf,0xd5,0x37,0xad,0x61,0x29,0xd3,0x33, -0x62,0x75,0x2f,0xb6,0xb1,0x8f,0x5b,0xbf,0x33,0x2f,0x3a,0x1a,0x73,0xc7,0x34,0xd7,0x1e,0xab,0x49,0x6b, -0xbb,0xb7,0xe0,0x52,0xad,0x43,0x81,0x3c,0x22,0xc2,0x72,0x48,0x94,0xae,0xf5,0x81,0x03,0xb8,0xda,0xf3, -0x4d,0x1a,0x6f,0xed,0x87,0x89,0x3b,0xf6,0x83,0x7b,0xd1,0xc8,0x59,0x3e,0x26,0x76,0x17,0x2f,0x21,0x1c, -0xdc,0x39,0x7f,0x1d,0x2b,0xd3,0x5d,0x50,0x26,0xb1,0x2c,0xaa,0xb4,0x67,0x51,0xf5,0x7f,0xaf,0x96,0x98, -0xf9,0xde,0x59,0x66,0x5b,0x0b,0xed,0xfb,0x86,0x17,0x5e,0xba,0xdf,0x5a,0x73,0xad,0x0c,0x5a,0x63,0x66, -0x1f,0xc5,0xba,0x81,0x6c,0x68,0x35,0x9a,0xa1,0x13,0xed,0x76,0x9f,0x35,0xf1,0x4e,0x4d,0x15,0xfa,0x86, -0x2d,0xc9,0x40,0x29,0xb5,0xee,0xd6,0x8a,0x1b,0xb4,0xb1,0xd1,0x4e,0xf2,0x9e,0xef,0xbe,0x5b,0xf6,0x7c, -0x15,0xde,0xf1,0xe7,0xc6,0xd6,0x5e,0xe4,0x66,0xbe,0xd7,0xc0,0x36,0xd5,0xd8,0x2a,0x70,0xe5,0x21,0xb8, -0xd9,0xd6,0xb4,0xab,0xa5,0xa4,0x64,0xbf,0x14,0x88,0xa6,0x9b,0xf9,0xa0,0x56,0x63,0xcf,0x3c,0xd7,0x6b, -0xc0,0xd7,0x3a,0x66,0x6b,0xc6,0x59,0x79,0x33,0xf0,0x13,0xe7,0x5e,0x89,0xce,0x79,0x4b,0x23,0xcd,0x1e, -0xfa,0xa1,0x56,0x7e,0x7c,0x1b,0x6f,0x69,0x61,0xfb,0x78,0xe9,0x9e,0x3e,0x7b,0x46,0x99,0x49,0xed,0x56, -0xe6,0xc4,0xb4,0xdc,0x62,0x86,0xdc,0x83,0x55,0xb3,0x97,0xa8,0xd9,0x67,0x3e,0x91,0x99,0xbf,0xff,0xf9, -0xa6,0x7d,0x32,0xb1,0xf6,0xa6,0x94,0x5f,0x67,0x71,0xdf,0x97,0x83,0xc3,0xd0,0x65,0x8b,0xf7,0xf6,0xee, -0xb4,0xc5,0x27,0x47,0x7f,0x85,0xf9,0xc3,0x7e,0xfc,0x99,0x3e,0xa6,0xeb,0xa9,0x1f,0xab,0xda,0x7c,0x98, -0xe1,0xda,0xcf,0xac,0x59,0xc1,0xe7,0xec,0x86,0x48,0x74,0xf8,0x05,0xa9,0x75,0x7b,0x67,0xdb,0xba,0xbd, -0xb6,0x88,0xcc,0x9f,0xd8,0x6b,0xdb,0x45,0x69,0x22,0xd8,0x53,0xd8,0xe8,0x43,0xdb,0x72,0x27,0xaf,0x70, -0x3b,0xb3,0xf6,0xf1,0x94,0xb9,0xbd,0xad,0x37,0xc4,0xa0,0x9f,0x69,0xec,0x6e,0xda,0x8c,0xfa,0xd0,0xde, -0x11,0x8d,0xdd,0x5d,0x97,0xc7,0xfc,0x13,0x9c,0xe4,0x6e,0xb3,0xb5,0xee,0xed,0xb1,0x86,0x21,0x39,0x01, -0x7c,0x78,0x87,0x29,0xd8,0xaf,0x83,0xfb,0xd2,0x48,0x7a,0xf3,0xf6,0x02,0x74,0xa0,0x58,0xcc,0x59,0x92, -0x6b,0xf6,0x66,0xed,0xee,0x63,0x71,0x88,0xcc,0xbb,0xf4,0xf7,0xc4,0x77,0xcb,0xfe,0x7e,0xf8,0x1f,0x6f, -0xb3,0x55,0x45,0x62,0xb3,0xb8,0x86,0xb4,0x8b,0xda,0xf2,0xbe,0xf8,0xc6,0x04,0x1b,0x85,0xd1,0xaa,0x2d, -0xcd,0x88,0xbc,0x97,0xdf,0x7a,0xa1,0x2b,0x8e,0xa1,0x67,0x4f,0x9e,0x78,0xa1,0x2d,0x3d,0x83,0xa3,0x56, -0x4b,0x34,0x86,0x47,0xce,0x0c,0x89,0x3c,0x4b,0xf4,0xa0,0x47,0xdd,0x0b,0x5d,0x59,0x93,0x93,0xc8,0xe4, -0xe5,0x85,0xb6,0x08,0xc6,0x49,0xf3,0x5c,0x5e,0xe8,0x14,0x4a,0xa8,0xd4,0x93,0xe4,0xec,0xcc,0x0b,0x2d, -0xc1,0x83,0x93,0x42,0x1a,0x61,0xde,0x37,0xf2,0x83,0x9e,0x54,0xf2,0x56,0xa7,0x6d,0x04,0x02,0x3d,0x49, -0x5f,0x8b,0x06,0xd1,0x99,0x42,0xd1,0x17,0xa1,0x7d,0xa8,0x8b,0x0e,0xf5,0xbd,0x50,0x82,0xe8,0xf3,0xb0, -0x45,0xfe,0xe8,0x03,0x2d,0x5b,0xa5,0x22,0x96,0x28,0xe2,0x0d,0x74,0x54,0x5e,0xa8,0xf9,0x3d,0x5b,0x3f, -0xbe,0xa1,0x71,0x85,0x95,0xe0,0x9d,0xa1,0x95,0x54,0xc8,0x6a,0xf6,0xf2,0x8d,0x96,0x0e,0xc6,0x69,0xc8, -0x07,0x79,0x3b,0x4d,0x6b,0x4b,0xc0,0xd9,0x9c,0x4e,0xe6,0xe1,0x45,0x58,0x84,0x65,0xb8,0x08,0xe7,0xe1, -0x69,0xb8,0x0a,0x97,0x63,0x89,0x48,0x79,0x78,0xd4,0x55,0x1d,0xe5,0x62,0xbe,0xd2,0x58,0x89,0x8d,0x80, -0xac,0x0b,0xcd,0x24,0x4b,0x0e,0xfc,0xb9,0xbe,0x38,0x8d,0x33,0x58,0x51,0x4c,0x4e,0x8d,0xd0,0x58,0x07, -0xab,0x9a,0xcc,0xa3,0x66,0x56,0x36,0x22,0xe5,0x95,0x34,0x40,0x1b,0x1b,0x47,0x06,0x54,0x39,0xe0,0x48, -0x4b,0x8b,0x78,0xd5,0xc4,0x10,0x16,0x50,0xeb,0x3a,0x5e,0x01,0xd1,0x3a,0x89,0xef,0xf8,0xb4,0x4f,0xb2, -0x94,0xba,0xd2,0x96,0x39,0xc9,0xc4,0xbf,0xe0,0x1a,0x84,0x45,0x7c,0xef,0xc8,0xc0,0x45,0xeb,0xfa,0x23, -0x24,0x26,0xea,0xad,0x2a,0xbb,0x8c,0x93,0xe9,0xc5,0x8c,0x11,0x5a,0x35,0x80,0x69,0x41,0xd4,0x97,0xbd, -0x9a,0x68,0x0f,0xe7,0x96,0xb8,0xf8,0x0a,0xd2,0xb3,0x56,0x67,0x6f,0xd5,0xb2,0x28,0x08,0x77,0x76,0x3b, -0xbc,0xe1,0xfd,0xcf,0x91,0xc7,0x87,0x37,0xee,0x12,0x3b,0xec,0xac,0x27,0x55,0xc8,0x2d,0x8b,0x49,0xa5, -0xd8,0xbe,0x92,0x54,0x82,0xad,0xcb,0xc8,0x79,0xdf,0x5d,0x43,0xea,0xf5,0x6d,0x0b,0xc8,0x49,0x72,0xcb, -0xea,0x71,0xd2,0xe9,0xa5,0xd3,0xcc,0xfc,0xa6,0x43,0x3d,0xbd,0xc1,0x59,0xd3,0x57,0x82,0xf3,0x59,0xe1, -0x34,0x3b,0x7a,0x34,0xa3,0x15,0x01,0x2f,0xf4,0x22,0xad,0x2a,0x22,0x8e,0x15,0x4d,0xf6,0x4b,0x75,0x39, -0x3d,0x9c,0xc5,0xde,0x6b,0x62,0xb9,0xea,0x74,0x67,0xb5,0xa4,0x82,0xd3,0x1d,0x66,0xe8,0xd0,0xad,0x26, -0xcd,0x3d,0x4a,0xf3,0xf2,0xed,0x83,0xed,0x09,0x3e,0xa3,0x04,0x6c,0x55,0xb8,0x03,0x59,0x03,0xd1,0xf2, -0x1d,0x34,0x61,0xd7,0x4a,0xf1,0x39,0xa5,0x78,0x7b,0x91,0xee,0x00,0x64,0x6c,0x67,0x5e,0xa4,0x62,0x60, -0xbd,0x28,0x8a,0xdf,0x76,0x16,0xd9,0x6f,0xe9,0x4e,0xb2,0x23,0xc0,0x85,0x34,0x94,0x67,0xd9,0xb9,0x8e, -0xca,0x0c,0xdb,0x66,0xe2,0xf1,0x28,0xdf,0xac,0xa2,0x57,0x65,0xb9,0x5a,0xba,0x05,0x7f,0x41,0xd9,0x0a, -0x39,0xa8,0x76,0xaa,0xe4,0x5d,0x3a,0x1f,0xee,0xfc,0x54,0xac,0x76,0x88,0xe6,0xac,0x16,0xf3,0x9d,0x32, -0x3d,0x29,0xa8,0x94,0xf7,0xc5,0xaa,0xdc,0x39,0x29,0x92,0x72,0x4e,0x85,0x5e,0x59,0x5f,0xff,0x95,0xbe, -0x7e,0xa5,0xfc,0xd0,0x2a,0xaa,0x15,0xd7,0x89,0x61,0x34,0xec,0xaa,0xff,0xad,0x5d,0x86,0xf5,0xee,0x2b, -0x7a,0xf7,0x6d,0xa1,0xe0,0x51,0x29,0x8b,0xb4,0x66,0x88,0x74,0x2b,0xc5,0x21,0x2c,0xc5,0xdf,0xd0,0x1d, -0xab,0xa6,0xae,0x97,0x59,0x99,0xce,0xc3,0x9d,0xe5,0x22,0x4d,0xe0,0x90,0x9d,0xb2,0xd3,0x05,0x76,0xac, -0xe1,0x70,0xe8,0x6d,0xcc,0x68,0x55,0xc4,0xb2,0x15,0x25,0x63,0x3e,0x1a,0xaf,0xcf,0xa9,0xf7,0xe8,0xe9, -0x5b,0x2f,0xf4,0x1e,0xd1,0x68,0x27,0xb0,0xd8,0x7c,0x7c,0x49,0x29,0x1f,0xd0,0x4e,0x58,0x9c,0x9b,0xbb, -0x47,0x0f,0x0f,0xef,0x1d,0x36,0x77,0x6f,0x0e,0x7f,0x3c,0xfc,0x82,0x6e,0x9f,0x3e,0xff,0xe1,0x6f,0xa3, -0xc3,0x7b,0x74,0xf5,0xfd,0x57,0xf7,0xbe,0x3c,0x7c,0x82,0x14,0x0f,0x9f,0x1e,0x7e,0xf1,0xe5,0x88,0xae, -0x4c,0x16,0x8f,0x68,0x63,0xad,0x93,0x05,0x5e,0x0a,0x30,0x72,0xe8,0xbd,0x7a,0xf1,0xe6,0xc7,0xd1,0xe8, -0x33,0xba,0xfa,0xfa,0xc5,0x8f,0xf7,0xfe,0x86,0xe4,0x2f,0x9e,0xfe,0xeb,0xf0,0x2b,0xfa,0x7d,0xf3,0xec, -0xaf,0x23,0x2e,0xeb,0xcd,0xd3,0xb7,0x9f,0xfd,0xb8,0xf3,0xec,0xde,0x43,0xa4,0x7a,0x7a,0xf8,0xd7,0x2f, -0x46,0x9e,0xb1,0x93,0x23,0x92,0x09,0x97,0xa8,0x23,0xb6,0x04,0x14,0x5d,0xfb,0x34,0xdd,0x3f,0x9c,0x09, -0x56,0x8d,0x69,0xef,0x65,0x72,0x4e,0xf3,0x73,0x25,0x96,0x11,0x76,0x93,0xdf,0xa6,0x97,0x50,0x9e,0x52, -0x5e,0x10,0xe1,0x3e,0x5d,0x5d,0x66,0x73,0x8e,0x36,0xed,0xbd,0x02,0xe2,0xac,0x3c,0x7d,0x28,0x9c,0x04, -0x1a,0x57,0x2c,0x6a,0xea,0x4b,0xb4,0x89,0x51,0x3c,0x76,0x5e,0x41,0x97,0x8b,0xdb,0xa5,0x28,0x6b,0xcc, -0x83,0xd7,0x69,0xe2,0xa6,0xe0,0xdf,0x9d,0x27,0xf4,0x94,0x6d,0x63,0x1f,0x13,0xd5,0x38,0x7f,0x6f,0x2e, -0x76,0xfc,0x79,0x4a,0x59,0x07,0x1f,0xec,0xad,0xc3,0xe1,0x88,0x7f,0xef,0x0d,0xbf,0x90,0x7b,0xdc,0x3e, -0x7c,0x89,0x9e,0x7f,0xbe,0xba,0xfe,0xf3,0xfd,0xc2,0xab,0xcb,0xee,0x98,0x97,0xff,0xa0,0x2c,0x5f,0xae, -0xea,0x9d,0xe2,0x6c,0xe7,0x35,0x66,0x1f,0xdd,0xfe,0x90,0x94,0x97,0x58,0x7c,0xdf,0xc1,0xbc,0x48,0x79, -0xa0,0xe1,0x71,0x59,0xd0,0xc3,0x67,0x8f,0x50,0x93,0xd7,0x0f,0x77,0xb4,0xf9,0x2f,0x0d,0x98,0xb9,0xfe, -0xe6,0xd5,0xb3,0x97,0xea,0xc6,0x54,0x71,0xa4,0xaa,0x68,0xd7,0x70,0x16,0xa9,0x75,0x0e,0xa3,0x1e,0x53, -0x4b,0xde,0x99,0xf4,0x42,0x6a,0x2a,0x09,0xe4,0xc0,0x78,0x78,0x77,0xfa,0x60,0xff,0x5f,0xc7,0xf3,0x59, -0x20,0x37,0xc9,0xfe,0x1f,0xb3,0x60,0x7a,0x7c,0xf5,0xef,0xdd,0xff,0xfa,0xe4,0xce,0x5f,0x7e,0xde,0xbb, -0x7b,0xec,0x1f,0x07,0x47,0xf7,0xc3,0xe1,0xf1,0x64,0x1c,0xdd,0x6c,0x80,0x51,0x7a,0x7c,0xbc,0x9e,0xdd, -0x7c,0x11,0x6e,0xee,0x1c,0x58,0x78,0xd8,0x82,0xf1,0xd8,0x94,0xf9,0x47,0x5a,0x16,0xaf,0x92,0x79,0x2b, -0x50,0x42,0xec,0x79,0x21,0xc2,0x08,0x25,0x47,0xf5,0x38,0xa1,0x1d,0x31,0x1f,0xc4,0xde,0xc8,0x53,0xd9, -0xf8,0xf9,0x20,0x0d,0x94,0xc9,0x39,0x71,0xba,0x4d,0x5e,0x4c,0x7a,0x88,0xb2,0x3d,0x29,0xca,0xcb,0xa6, -0xfa,0x77,0x54,0xa0,0xd0,0x29,0x3c,0x56,0xe3,0x4f,0x93,0x39,0xf5,0x2d,0x1a,0xf9,0xe9,0x0c,0x47,0x52, -0xf1,0x46,0xf7,0x35,0xa2,0x24,0xec,0x24,0x2d,0xeb,0xf3,0x5d,0xb7,0x4b,0x9a,0x18,0x06,0xc9,0x22,0x85, -0xcb,0x17,0x48,0xa1,0xf6,0x80,0x05,0x7d,0xda,0xb9,0x00,0xca,0x32,0xef,0x12,0xe9,0x1c,0xc4,0x0e,0x94, -0x88,0xab,0x15,0xee,0x64,0x44,0x93,0x56,0x55,0x2d,0x49,0x12,0x22,0x9a,0x44,0x3a,0xea,0x9d,0x2f,0x18, -0x73,0x90,0xa6,0x2b,0x0c,0xa7,0x77,0x0e,0x89,0x94,0xd2,0xfc,0x3d,0x05,0x51,0xa1,0x9d,0x84,0xee,0x57, -0x80,0xa3,0xe1,0x7b,0x1a,0x2d,0xf1,0xfb,0xdc,0xf5,0xc0,0x02,0x8f,0xa5,0xa3,0x3e,0xd0,0x3a,0x20,0xa2, -0xf8,0x2d,0xb8,0xcc,0x5a,0x42,0xf5,0xa8,0x26,0x34,0x84,0x93,0x56,0xd6,0xce,0x3c,0x3b,0x3b,0x4b,0xb1, -0xc2,0xa4,0x10,0xab,0x73,0x71,0x04,0x05,0x27,0x62,0xfa,0xf5,0xc6,0x04,0x59,0xd7,0x75,0x50,0xc1,0x41, -0xb8,0xe0,0x3e,0x2f,0x7a,0x68,0xd4,0x78,0x7b,0x53,0x8a,0x1d,0x54,0x59,0x5c,0x97,0xc4,0x0e,0xd8,0xc3, -0xae,0xc2,0x0f,0x89,0xaf,0x50,0x3d,0xcd,0xe1,0x8d,0xca,0xb3,0x13,0x78,0x40,0xb5,0x1f,0x1b,0x4e,0x2a, -0x6e,0x65,0x2c,0x21,0x15,0x02,0x09,0xed,0xa2,0x5f,0xb5,0x4e,0xc5,0x87,0xd1,0x48,0xa0,0xa7,0xb8,0x00, -0x15,0x6e,0xb3,0x37,0x1b,0xc6,0x07,0xeb,0xcf,0x45,0xd7,0xc6,0x2d,0x89,0x7b,0x5b,0xa0,0x3a,0x7a,0x5e, -0x8c,0x53,0x76,0x8c,0x9e,0xb4,0xe3,0x63,0xd0,0xaa,0xe4,0xa0,0x34,0x30,0xa0,0x9c,0xe2,0x2f,0x30,0x16, -0xe8,0x47,0x3c,0x82,0x04,0x9d,0x36,0x88,0xb2,0xea,0x17,0x0e,0x4d,0x62,0x6c,0x48,0xd2,0xe0,0x7e,0x3c, -0x9a,0xc8,0x57,0x9c,0x68,0x16,0xf1,0x8d,0x04,0xb8,0x00,0xb3,0xd1,0x8c,0x61,0x09,0x07,0x39,0x0d,0x63, -0x6c,0x9b,0x72,0x7a,0xe3,0xda,0xb2,0x56,0xd7,0x21,0x1f,0xb0,0xea,0x92,0x93,0x53,0x62,0x69,0xcf,0x2f, -0xb2,0x5f,0x7f,0x5b,0x5c,0xe6,0xc5,0xf2,0x77,0x5a,0x2d,0xab,0x77,0x57,0xd7,0xef,0xff,0xe0,0x88,0x0b, -0xe6,0xa3,0x07,0xf6,0x47,0x0f,0xbe,0x7e,0xf8,0xe8,0xf1,0x93,0x6f,0x9e,0x3e,0xfb,0xfb,0x3f,0x9e,0xbf, -0xf8,0xf6,0xe5,0xab,0x7f,0xbe,0x7e,0xf3,0xf6,0xbb,0xef,0x7f,0xf8,0xf1,0xa7,0x7f,0xb9,0x1f,0x7d,0x62, -0x7f,0x44,0xfb,0xda,0x67,0x9f,0x7f,0xf1,0xe5,0x5f,0xff,0xf6,0x95,0x9b,0xe8,0xbf,0xba,0x39,0xbb,0x09, -0x76,0xed,0x04,0xff,0xfe,0xdf,0x9a,0x20,0xf9,0xc1,0x2f,0x83,0x7d,0x9a,0xa5,0xd3,0x59,0x74,0xec,0x8d, -0x3f,0x3d,0xba,0x3f,0x09,0x87,0x07,0xeb,0xe3,0x63,0xe5,0xe7,0x2d,0x46,0x8a,0x44,0x67,0xca,0x38,0x1d, -0x97,0xf7,0x47,0xe3,0xfd,0xfd,0x32,0x48,0x06,0x71,0x3e,0xe5,0x93,0x75,0x09,0xab,0x66,0x5f,0x2e,0xb9, -0xd7,0xfc,0xe0,0xae,0xaf,0xc1,0x1e,0xf6,0x0f,0x83,0xa0,0x09,0xcd,0x64,0xaf,0x91,0x1c,0x9b,0x5c,0xfa, -0xe0,0xd5,0xb3,0x7f,0xa4,0xef,0xcd,0xac,0x77,0xba,0xfd,0xf0,0xcb,0xd0,0xfb,0xaf,0x4f,0x1a,0x63,0xc6, -0x3b,0xfe,0xa7,0xd6,0x02,0xf6,0x92,0x65,0x46,0x9f,0x7a,0xb3,0x4f,0x65,0xb6,0xa4,0x7c,0xda,0xb5,0x17, -0xe1,0xdf,0x2b,0xe5,0xcc,0xd9,0x80,0x14,0x34,0xe6,0x66,0x20,0xad,0x06,0x9d,0xa0,0x89,0x42,0x65,0xbe, -0x9f,0x17,0xaf,0x99,0x55,0x61,0x4b,0xb7,0xb8,0x37,0xde,0xef,0x64,0x14,0x19,0x45,0x13,0x95,0xde,0xef, -0x03,0x7d,0xc5,0x76,0x95,0x8d,0xdb,0x93,0x30,0x40,0x2c,0x4e,0x0f,0xec,0xd2,0xbe,0x63,0x4e,0xd3,0x5a, -0xfe,0xde,0x27,0xf0,0x11,0x7b,0x93,0xbc,0x53,0x0b,0xbf,0x45,0xb2,0x1b,0x64,0x0c,0x4d,0x6c,0xc6,0x57, -0xe9,0x49,0x55,0x9c,0xfe,0x26,0x9e,0xd5,0xdc,0x52,0x71,0x11,0xcb,0xce,0xde,0xfb,0x37,0xc2,0x66,0xc2, -0xe5,0x07,0xb2,0x45,0x6f,0xb8,0xbc,0x2a,0x1f,0x5f,0x2f,0x85,0x77,0x93,0x0e,0x1c,0xf1,0x0b,0x9b,0x44, -0x52,0x9a,0xd7,0x80,0xc4,0x7e,0x48,0x45,0x9f,0x08,0x83,0x4a,0xc4,0x32,0xe8,0x28,0x41,0x0e,0x03,0x87, -0x45,0xf7,0x94,0x40,0x15,0x51,0x82,0x57,0x97,0xc2,0x48,0xce,0xe9,0xfc,0xd6,0xdf,0x41,0xb0,0xe7,0x5d, -0x5d,0xbe,0x66,0xc6,0xf5,0xfe,0x48,0xb7,0x5f,0x75,0x1b,0xd7,0x9a,0xda,0xeb,0xfd,0xa4,0x77,0x8c,0xfa, -0xff,0xed,0xee,0x59,0x98,0xdb,0xb6,0x91,0xfe,0x2b,0x32,0xdb,0x38,0xa2,0x45,0xd1,0x92,0x1b,0xa7,0x3d, -0x29,0xb4,0xc6,0x71,0xd3,0xc4,0x33,0xcd,0xa3,0x89,0xaf,0xf9,0x6e,0x52,0x9f,0x87,0xb2,0x68,0x89,0x8d, -0x2c,0xea,0x48,0x4a,0x4e,0xce,0xf5,0x7f,0xff,0xf6,0x01,0x80,0x00,0x09,0xea,0xe1,0xa4,0xfd,0xee,0xbe, -0xce,0xa4,0x16,0x81,0x05,0xb0,0x58,0x3c,0x77,0xb1,0x8f,0x44,0x5e,0x72,0x73,0x38,0x51,0xf8,0x8e,0x0b, -0x84,0xa2,0x2f,0x79,0x29,0x05,0x98,0x3c,0x84,0x2b,0x76,0x04,0x3b,0xf4,0x65,0xee,0xe1,0x3d,0x17,0x4f, -0x9c,0x9b,0x10,0xae,0x43,0x90,0x07,0x9f,0x70,0xc2,0xc0,0xc5,0x78,0x00,0x94,0xed,0x12,0x63,0x86,0xa3, -0x8d,0x95,0x36,0x71,0x23,0x97,0x7b,0x1d,0xa1,0x05,0x18,0xcc,0xa0,0x92,0x4d,0x31,0x13,0xe0,0x84,0x02, -0x60,0xf4,0x3e,0xfe,0x29,0xfe,0x4a,0xe8,0x89,0x9a,0xab,0x18,0xe2,0x7c,0xda,0x14,0x3d,0xba,0x7c,0xe7, -0x74,0x14,0x8f,0x29,0x29,0x8b,0x22,0xfa,0x46,0x45,0x2a,0x38,0x63,0x05,0x8a,0x9b,0xe2,0x24,0xa6,0x32, -0xf9,0x4d,0x7f,0x2d,0x84,0x54,0xa8,0xae,0xe5,0x75,0xa3,0xef,0xa4,0xd2,0x96,0xbe,0x28,0x71,0x9a,0x8f, -0xe1,0x04,0x31,0xe6,0xb9,0x3e,0xe3,0x16,0x9c,0x8d,0xb3,0x0c,0x05,0x5b,0x78,0xca,0xc9,0xf0,0x11,0xd6, -0x25,0x58,0xba,0x64,0xfc,0x84,0x37,0x94,0xe2,0x76,0x41,0xfd,0xa3,0xf8,0x0d,0x21,0xb3,0x61,0x57,0x69, -0x72,0xcd,0xcc,0x11,0xaa,0x13,0xa2,0x62,0xb3,0x5f,0xdc,0x10,0x2a,0xf7,0x1f,0x0d,0x19,0x3e,0x8f,0x64, -0x6c,0x07,0xdc,0x19,0x65,0xb8,0x91,0x00,0x25,0x04,0xb8,0x26,0x71,0x15,0x2a,0x86,0x5f,0x1a,0xc9,0x39, -0xa2,0x0e,0x87,0x4c,0x6c,0xbc,0x6f,0x35,0x0b,0x3d,0x58,0xad,0xe8,0x29,0xb0,0x55,0x80,0xb0,0x9f,0x24, -0xb2,0xec,0x93,0xfe,0x98,0x84,0x77,0xa4,0xae,0xe1,0x9e,0x19,0x3e,0x0d,0x2f,0xce,0x5d,0xe5,0xb6,0xc9, -0xd4,0x34,0xc6,0x3d,0x44,0x54,0xde,0x86,0x02,0x63,0xe4,0x1f,0x00,0xf1,0x49,0x8c,0xf4,0xf7,0xf0,0x3e, -0x4d,0x5a,0x0b,0x05,0xed,0xae,0x6f,0xf0,0x62,0x43,0xbe,0xf0,0xe1,0x36,0x85,0x83,0x8b,0x9c,0x1b,0xaf, -0x31,0x5e,0x74,0x68,0xbc,0xd4,0x38,0x83,0x13,0x9a,0x27,0xd0,0x4d,0x3c,0x9d,0x36,0x86,0xc8,0xd5,0xd1, -0x82,0xc7,0x8b,0xdc,0x0c,0xee,0x69,0x19,0x4e,0xd6,0x51,0x46,0xc1,0x8f,0xe4,0x2c,0x39,0x84,0x19,0xe1, -0xf6,0x8a,0xcb,0x20,0x34,0x84,0x46,0xc7,0xe1,0x8c,0x0d,0xf0,0x1b,0xb0,0x49,0xe3,0x45,0x1e,0x86,0x8c, -0x5b,0xa6,0x59,0x89,0xb4,0x25,0x74,0x14,0xff,0x08,0x60,0x8d,0x70,0x1c,0x42,0x33,0x4d,0x8a,0x45,0xe8, -0xfa,0xa8,0xe2,0xf2,0x69,0x92,0xea,0xc2,0xb1,0x9a,0x8e,0x03,0x8f,0x7c,0x23,0x22,0xd9,0xc3,0xc4,0xb3, -0x79,0x9c,0x51,0xaf,0xc9,0x8c,0x03,0x0a,0xaa,0xf9,0x57,0x35,0x32,0x84,0xa3,0x2a,0x36,0xbc,0x18,0x44, -0xe2,0xdc,0x3b,0xa1,0xf9,0x15,0x52,0xd4,0xa1,0x6f,0x35,0x60,0x71,0x61,0xba,0x95,0x2e,0xd4,0x05,0x91, -0xaf,0xc3,0x4f,0x3d,0xd4,0xc4,0x05,0xee,0x0a,0x9f,0x74,0xc8,0xab,0x02,0xde,0x48,0xca,0x8b,0x07,0x0f, -0x00,0x75,0xc7,0x2e,0x9f,0x15,0x32,0xe3,0x6b,0x9f,0x17,0xd6,0x85,0x2c,0xf6,0x4b,0xe1,0xb8,0xc1,0x7e, -0x40,0xa2,0x03,0xd5,0xe2,0x04,0x90,0x7b,0x54,0x5e,0xd9,0xa3,0xde,0x25,0xd7,0xc5,0xee,0x48,0x2b,0x17, -0x99,0x81,0x61,0x14,0xcd,0x58,0xfc,0xd0,0xf8,0x1c,0x55,0xb7,0xc9,0x8c,0x56,0xf8,0x24,0xba,0x6e,0x10, -0x5f,0x32,0xe0,0x5e,0xc3,0xde,0xa4,0x42,0x55,0x14,0x87,0xea,0x1d,0x5f,0x9c,0xed,0xad,0x1f,0xc3,0x54, -0xc4,0x8a,0x91,0xb7,0x36,0x5a,0xd0,0xce,0x99,0x51,0xb4,0x04,0x1e,0x4a,0xb4,0xd1,0x29,0xda,0x00,0x9a, -0x88,0xc6,0x56,0x12,0x33,0x24,0xaa,0xa1,0xd7,0x70,0xac,0x91,0x62,0x38,0x1a,0x0b,0xc3,0x2b,0xd3,0x56, -0x6e,0xf6,0xff,0x9f,0xc9,0x3b,0x8a,0x33,0x79,0x5a,0xd2,0xbe,0x4c,0x47,0x24,0x0b,0x36,0x1a,0xef,0x4f, -0x7f,0x3a,0x85,0xd5,0x9f,0xc3,0x74,0xfe,0xf8,0x15,0xa8,0x2e,0xda,0x59,0x4b,0xf8,0xa7,0x24,0x7d,0x2b, -0xde,0x86,0x95,0x91,0x4b,0x11,0x9b,0xe4,0xe9,0xe7,0x53,0xd8,0xd6,0xf1,0x31,0x98,0x96,0x2e,0x06,0x25, -0xc9,0xd2,0xcb,0x40,0xed,0xe6,0xbc,0x6e,0x1c,0xa3,0xe2,0x64,0xf6,0x13,0x9c,0x3e,0x7f,0x9f,0xcb,0xfb, -0x24,0x13,0x4a,0xca,0xba,0x23,0xd2,0x2c,0x92,0xb6,0x2a,0xf9,0x1f,0x7f,0xe0,0xff,0x4d,0xfb,0x4e,0xc5, -0xc3,0xa2,0x27,0x11,0x56,0xcb,0x66,0x76,0x09,0xd8,0x11,0xbe,0x9d,0x97,0xa9,0x8e,0x81,0xb3,0xe2,0x64, -0x91,0xc1,0x5e,0xcc,0x3b,0x9c,0xda,0xab,0xd1,0x4b,0xd4,0x4d,0x1a,0xe7,0xb0,0x8d,0xf9,0x8d,0x15,0x73, -0x1f,0x23,0x26,0x70,0xac,0x7a,0x55,0x47,0x31,0x12,0xa1,0x89,0x58,0xca,0xa7,0x20,0xf4,0xe5,0x2d,0x79, -0x23,0x2a,0x42,0x7f,0x08,0x6f,0x44,0x36,0x8f,0x6e,0xe2,0x7e,0x2e,0x02,0xfd,0x88,0x10,0x59,0x6e,0x3f, -0x1f,0x6c,0x38,0xa8,0x84,0x60,0x61,0xc9,0x2e,0x0f,0x17,0x4d,0x00,0xeb,0xa2,0x1f,0x0a,0x34,0x49,0x39, -0x26,0x3f,0x4d,0x18,0x95,0xb9,0xbc,0xd0,0xa8,0x12,0x35,0xe0,0x85,0x02,0x8e,0xb2,0xb9,0x12,0x84,0x2d, -0xfa,0x36,0xd0,0x04,0x1a,0x74,0xa9,0x00,0x16,0xa6,0x11,0x67,0xb3,0x87,0x18,0x25,0x6a,0x8e,0xfe,0x6d, -0x60,0x45,0x25,0xfc,0x48,0xd0,0x10,0xcf,0xd7,0xb8,0xc2,0x30,0x00,0x21,0x1f,0x4c,0x6a,0xe2,0x50,0xb8, -0xaa,0x66,0x19,0xa9,0x33,0x0a,0x78,0xac,0x33,0x9d,0x05,0x97,0x21,0xd8,0x6d,0xf6,0x64,0xa2,0xce,0xab, -0x0d,0x09,0x36,0x0d,0x3f,0x0b,0x72,0xdd,0xc6,0x23,0x74,0xf6,0x48,0x1e,0xac,0x7a,0x39,0x32,0xf8,0x77, -0xb8,0x34,0x74,0x3c,0xf0,0xb0,0x7c,0x13,0xce,0xa2,0x29,0x9f,0xa7,0xc0,0x34,0xc1,0xef,0xe2,0xf6,0x80, -0x3d,0x71,0x5a,0xa6,0x10,0x40,0x60,0x25,0xce,0x59,0x02,0x81,0x26,0xc9,0x9d,0x67,0x11,0x39,0xd9,0x61, -0x29,0x24,0x7a,0x68,0xe1,0xc8,0xce,0x2f,0xa3,0xd9,0xa2,0xa9,0xb1,0x1e,0xe4,0x3b,0xe8,0xa1,0x14,0x58, -0xd0,0xe5,0xcb,0x60,0x2e,0x2c,0x7a,0xff,0x65,0x10,0xc5,0x7f,0x14,0xdd,0xd1,0xdb,0xba,0x35,0x30,0xd3, -0xe3,0x4b,0x2b,0xe4,0x08,0x79,0x8a,0xe7,0xb5,0x0e,0xe0,0xe7,0x78,0xf6,0xb1,0x0e,0x48,0x93,0x17,0x92, -0xbf,0x8a,0xb7,0x38,0x04,0xa7,0xa3,0x4f,0x99,0x21,0x72,0xfb,0x06,0x38,0x5e,0xb8,0x59,0x5d,0xfe,0x9b, -0xb2,0xb3,0xc6,0x11,0xec,0x8c,0x4b,0x15,0xeb,0x88,0x9e,0xd0,0x9b,0xc8,0x7f,0xb8,0x85,0xcc,0x0f,0x4b, -0xa5,0xa2,0x32,0x94,0x17,0x23,0x39,0x1a,0xfe,0x1c,0x16,0x71,0x7b,0x4c,0x37,0x67,0x21,0x12,0x94,0xb7, -0x11,0x92,0x0c,0x8a,0xb8,0x54,0xdf,0x62,0x78,0x56,0xf6,0x63,0xe9,0xf6,0xa1,0x22,0x7a,0x08,0x02,0xde, -0xde,0x65,0x5f,0x0f,0xce,0xbb,0x9b,0x18,0xb8,0xe2,0x06,0x8c,0x6e,0x58,0x8c,0x0a,0xe5,0x6b,0xa2,0x28, -0xcf,0x19,0x09,0x7c,0x01,0x03,0x84,0x94,0x72,0xa0,0x70,0x48,0xc2,0x06,0xc7,0x7b,0xd4,0xc1,0x54,0x62, -0xcc,0xd1,0x15,0x9c,0x97,0x16,0xca,0xd3,0xe5,0x1e,0xa3,0x63,0xd4,0x12,0xa5,0x5e,0x4a,0x29,0x70,0x3d, -0xb5,0x14,0xc8,0xc6,0x14,0xbb,0xd6,0x2a,0xfd,0xca,0x54,0x2b,0x49,0xf3,0xa1,0xc7,0xec,0x10,0xaa,0xe5, -0x20,0x21,0x8b,0xf5,0x8b,0x19,0x44,0x20,0xe6,0xc2,0x01,0x6d,0x58,0x50,0xb3,0xbc,0xa8,0x88,0x20,0x90, -0xc4,0x6b,0x68,0xaf,0x7a,0xbf,0x01,0xf1,0xfd,0x78,0xf4,0xa9,0x66,0x00,0x0a,0x22,0x1a,0x83,0x00,0xb7, -0xdd,0x57,0x7c,0xf8,0x1a,0x97,0x4c,0x71,0x20,0xdb,0x08,0x1e,0x1d,0x05,0x70,0x87,0x15,0x85,0x32,0xc3, -0x2d,0x81,0xd8,0x2f,0x5f,0x86,0x9f,0x84,0x54,0x16,0x05,0xf8,0xaa,0xaa,0x14,0xc5,0x9f,0x28,0x83,0x10, -0x3c,0xd8,0x41,0xa7,0xd3,0xea,0x76,0xf6,0xe0,0x66,0xa3,0x37,0x29,0x87,0x0b,0x37,0x4d,0x69,0x87,0xe0, -0xd2,0xb3,0xaf,0x36,0x2c,0x4a,0x4c,0x14,0x0a,0x67,0x24,0x82,0x7e,0x55,0x11,0x6b,0x49,0x78,0xa9,0xe8, -0x96,0xc3,0x80,0xdf,0x21,0xe5,0x55,0x0d,0x3e,0x07,0x08,0x6b,0x8f,0xa2,0x69,0x5b,0xe0,0xe2,0xb0,0xf3, -0x30,0xda,0xbc,0x1d,0xb4,0xd9,0x14,0xbd,0xb6,0x96,0xbb,0x86,0xe3,0xc5,0x5e,0x10,0x73,0x54,0xc9,0x50, -0x1f,0x1c,0x49,0x1b,0xf4,0xef,0xa2,0x1d,0x0c,0xaa,0xa1,0x8a,0x8c,0x98,0x5f,0x7a,0x32,0xdc,0xa5,0xc5, -0x64,0x86,0x29,0x1a,0x15,0xfe,0x6e,0xb4,0xd7,0x95,0xa2,0xd1,0xcd,0x6a,0x71,0xfc,0x6b,0x3a,0x65,0x23, -0xb9,0xc5,0xe9,0xb5,0xe1,0x0b,0x2b,0x2f,0x61,0x73,0x89,0xa6,0xdb,0x6f,0x64,0x5f,0xba,0x1e,0x61,0x8e, -0x17,0x8b,0xc8,0xbe,0x71,0xd1,0xf1,0xe4,0x85,0xa5,0x95,0x90,0x8a,0x2d,0x08,0x4b,0x14,0x0a,0x07,0x58, -0x4a,0x3f,0x52,0x6e,0x95,0x0e,0x86,0x3c,0x9f,0x6d,0x6a,0x30,0x65,0x4d,0x99,0xcd,0x14,0x6c,0xee,0xf4, -0x95,0xa7,0x48,0x7a,0x42,0xf7,0x48,0x0b,0x5d,0x39,0x63,0x2b,0xe2,0x72,0x91,0xba,0x35,0xb4,0x29,0x89, -0xd1,0x78,0xc2,0x1f,0xcf,0x31,0xdc,0xb5,0xb1,0x5b,0x61,0x12,0x91,0x8f,0x00,0xaa,0xe3,0xc0,0x22,0x18, -0x21,0x53,0x21,0x7c,0x9e,0x02,0x13,0x84,0xaf,0x2e,0xa9,0xb6,0x47,0x21,0x63,0x54,0x03,0xfe,0x66,0x31, -0xcd,0xa2,0x32,0xfc,0x1c,0x13,0x2b,0x12,0x4b,0x9e,0x4b,0x70,0x31,0xb0,0x82,0x5f,0x5c,0x67,0x95,0x12, -0xd7,0xff,0xca,0xf3,0xe7,0xf8,0x4c,0x50,0x2e,0x41,0x6f,0x07,0x55,0x8c,0x14,0xfc,0xe9,0x6c,0x69,0x2d, -0x72,0x11,0xcf,0x96,0xb6,0x39,0xc6,0x83,0xe0,0x94,0x07,0xbb,0xd8,0x81,0xcd,0xb1,0xbe,0xbe,0xff,0xf1, -0xf6,0xa5,0x03,0xfd,0xa7,0x9e,0x6d,0xd0,0x21,0xd2,0xd3,0x20,0x05,0xe7,0x8d,0x57,0xe9,0xb5,0xfd,0x9c, -0x02,0xbe,0xe1,0x65,0x38,0x8b,0xaf,0xf8,0xa9,0x94,0x1e,0x45,0x63,0x14,0x41,0x5d,0x8b,0x44,0x0c,0xa6, -0x22,0x7f,0x7f,0x88,0xcf,0x7d,0x56,0x32,0xb8,0x88,0x47,0xc5,0xf3,0x58,0x43,0xcb,0xd7,0xf5,0x75,0xcc, -0x51,0x3a,0x49,0xa6,0x49,0xfa,0xf6,0xf9,0x53,0xe3,0x38,0xbc,0xc4,0x44,0xfb,0xf0,0x44,0x38,0x3c,0xda, -0x68,0x5e,0x8a,0xf2,0xf6,0xa1,0x99,0xb1,0xfa,0x92,0x1c,0x82,0x99,0xde,0x73,0x6e,0x84,0xf6,0x27,0xe3, -0xf5,0x83,0xd2,0xe9,0xf1,0xe3,0x66,0x12,0x45,0x53,0x42,0xf0,0x0d,0x1c,0x2c,0x51,0xda,0xbc,0xcd,0xa6, -0x31,0xc5,0xcc,0x71,0x6e,0xd2,0xf1,0x70,0xee,0x08,0x6f,0x97,0x9c,0xba,0xd0,0x3d,0x37,0x96,0x8f,0x80, -0x4a,0x55,0xe8,0xa4,0xfe,0x57,0x0a,0x07,0xef,0x39,0x97,0x28,0xbe,0x5a,0x2d,0x34,0x92,0xbc,0x06,0x23, -0x27,0x78,0x0d,0xc0,0xa1,0x87,0xc2,0x2c,0x3e,0x59,0x9d,0x6f,0x86,0xa4,0x92,0x3a,0x63,0x69,0x18,0x1d, -0x88,0x13,0x7e,0xcd,0xaf,0x45,0x4b,0xc4,0xba,0x5f,0x73,0x52,0x91,0x71,0x17,0x30,0x4d,0x62,0xb2,0xb9, -0xde,0xf6,0xa8,0x16,0xa8,0x49,0x8c,0xef,0x2c,0xf3,0xe0,0xc5,0xbb,0x5f,0xbf,0x68,0x1e,0x40,0xf9,0xbf, -0x7a,0x1e,0x4c,0xb2,0xe5,0x17,0xcf,0x03,0xfa,0x26,0xeb,0x39,0xb5,0xe6,0xbf,0x7b,0x0c,0x37,0x35,0x7f, -0x02,0x5b,0x81,0xa7,0xed,0x04,0xdd,0x0e,0xa6,0x66,0xd6,0xd4,0xe5,0x7d,0x66,0x10,0x60,0x0f,0x1c,0xbe, -0x75,0x3c,0x60,0xea,0x00,0x5f,0x5a,0xda,0x3b,0x2f,0x45,0x6a,0x69,0x48,0x8e,0x3a,0xac,0x8f,0x2c,0xd9, -0xea,0xda,0xb1,0x3b,0xc2,0xe0,0x73,0x51,0x1f,0x7d,0xd9,0xc2,0xdf,0x07,0xdf,0x79,0xe1,0x51,0x67,0x77, -0x91,0x45,0xef,0x27,0x31,0xba,0x3b,0x0e,0xdb,0xed,0xe2,0x61,0x34,0x0d,0xa2,0x76,0xe8,0x25,0x7a,0xbb, -0xf6,0xc1,0x8d,0x61,0xff,0x8d,0x9f,0x84,0xfd,0x58,0x6e,0xbc,0x59,0x90,0xb6,0x62,0x6f,0x04,0x25,0x93, -0xea,0x39,0xcb,0x83,0x04,0x04,0x30,0xf7,0x45,0xed,0xfc,0xaa,0x07,0xd9,0x6c,0x51,0xe9,0x3c,0xbb,0xb6, -0xb6,0x78,0xad,0xcd,0x36,0x5a,0x6b,0x33,0xb1,0xd6,0xf2,0x4d,0xd7,0x1a,0xd3,0x47,0x13,0x42,0xc8,0x00, -0xa1,0x79,0xb1,0x3f,0x88,0xd3,0x67,0x24,0xf9,0x51,0x31,0xc4,0x0d,0xa7,0xd5,0xcc,0x5a,0x5d,0x14,0xe0, -0x19,0xcb,0x42,0x0c,0x35,0x1e,0x0b,0x06,0xff,0xf2,0xf6,0x6a,0x88,0x2e,0x1d,0x8d,0x85,0x9a,0x72,0x1a, -0x0e,0xf7,0x34,0x1a,0xa3,0x09,0x85,0x1c,0x71,0x2f,0xd7,0x01,0x36,0x59,0x9d,0x30,0x43,0x76,0x3a,0x9a, -0x5a,0x87,0x49,0x11,0xba,0x99,0xcc,0xb6,0x63,0x43,0x90,0x28,0x6d,0xbc,0x3e,0x51,0xe1,0x4a,0x0e,0x4b, -0x6b,0xe0,0x68,0x44,0x71,0x0d,0x35,0x1f,0xde,0x19,0xad,0x48,0x96,0x03,0x3a,0xd1,0xc6,0x98,0x8a,0x33, -0x93,0xdf,0x80,0xe4,0x9f,0x31,0xb5,0xb6,0x0c,0xcc,0x68,0x0c,0x49,0x52,0x2e,0xf4,0x13,0x25,0xd7,0x96, -0xca,0x98,0x8c,0x66,0x19,0xf4,0xaa,0x08,0x04,0x33,0xee,0x40,0x82,0xf6,0xf8,0x28,0xac,0xa9,0x59,0x08, -0xa4,0x36,0x60,0x46,0xbc,0xe2,0x7d,0x0e,0x49,0xb4,0xd9,0x36,0x02,0xf5,0x33,0x29,0x8a,0x29,0x97,0x97, -0xc8,0xed,0x2a,0x39,0x98,0x85,0xda,0x2e,0xcd,0x4b,0x1d,0x5d,0x26,0xc7,0x9f,0x88,0xaf,0x18,0x86,0xaf, -0x86,0x30,0x8e,0xc5,0x9f,0x88,0x2e,0x8d,0xff,0x7d,0x91,0x15,0xc2,0x5b,0xa1,0x06,0x64,0x60,0xae,0xbd, -0x70,0x4a,0x9d,0x27,0x98,0x4d,0x17,0x24,0x01,0xa1,0xe0,0x77,0x32,0x9a,0x9d,0x2f,0x93,0xfb,0x04,0x20, -0x0c,0x85,0x08,0x86,0xdd,0x3c,0xc2,0x3d,0xd5,0x69,0x31,0x98,0x72,0xbd,0xf2,0xad,0xec,0x39,0x8a,0xf0, -0xda,0xe8,0x83,0x16,0x7d,0x34,0x16,0xdb,0x99,0x83,0xc2,0x7c,0xd5,0x16,0xd5,0x13,0xf9,0x32,0x0d,0x2a, -0x6c,0x73,0xa8,0x71,0xf5,0x3e,0x90,0xc7,0x39,0xaa,0xdf,0xdf,0x71,0xa8,0x1c,0xff,0x63,0x44,0x2c,0xb1, -0x0f,0x63,0xf9,0xac,0xec,0x84,0x11,0x7b,0x02,0xc4,0x7d,0xc9,0x5a,0x5a,0xe4,0x39,0x52,0xbc,0xdb,0x05, -0xf8,0xb0,0xee,0x8b,0x3c,0x53,0x7c,0x2a,0x78,0xef,0x8e,0x06,0xc0,0x97,0xa9,0xb9,0x7a,0xf3,0x93,0x30, -0x7a,0x25,0xb0,0x5b,0x3a,0xa1,0xb2,0x28,0xd5,0xa5,0x32,0x28,0x24,0x45,0x39,0x34,0x3e,0x01,0xfb,0x0c, -0xa2,0x3d,0xe9,0xe3,0xf3,0xbd,0x2b,0xf5,0xc9,0x4e,0x92,0xc5,0x0c,0xa3,0x1b,0xd0,0x6d,0x1a,0x13,0xe8, -0x37,0xf5,0x03,0xae,0x76,0x7a,0xc5,0xe6,0x4d,0x99,0xdd,0xcd,0x95,0xd8,0x2d,0x3a,0x6f,0x49,0xa8,0x5b, -0xbd,0x63,0x64,0xea,0xae,0x89,0xe1,0x8f,0xd0,0x43,0x20,0xa1,0x00,0xa7,0x3f,0x35,0x72,0x6b,0x5e,0xc0, -0xc4,0x8b,0x08,0x82,0xca,0x77,0x79,0x0f,0x25,0x26,0x9a,0xb6,0x5d,0xe8,0x4f,0x82,0xd9,0x87,0xce,0xf9, -0x3e,0xdc,0x53,0xbc,0xd0,0xcf,0xe0,0xa3,0x7b,0xbe,0x0f,0x17,0x11,0xf8,0x58,0xc2,0xc7,0x01,0x7f,0xdc, -0x03,0x4f,0xbe,0x0b,0xa1,0x9f,0x30,0xc4,0x50,0xbb,0xd1,0x6a,0xd4,0xa8,0xdc,0x75,0x99,0x4f,0xcc,0xcf, -0x0b,0xca,0xd0,0x51,0x6f,0xc0,0x08,0x46,0x29,0xe7,0xb0,0x60,0x8e,0x3a,0xde,0x24,0xf9,0xe5,0x2d,0x44, -0x4c,0x1d,0xf9,0x19,0x70,0xbd,0x8e,0xc6,0x27,0xa9,0x41,0x92,0x0c,0x8e,0x28,0x22,0x3f,0x8b,0x22,0x4a, -0x6c,0x57,0x99,0x24,0x5a,0x9e,0xfe,0x08,0xa1,0x4b,0xfa,0x18,0xcf,0x9b,0xf8,0x2a,0x2e,0xa6,0x08,0xb2, -0xbb,0xef,0x78,0x89,0x17,0x53,0x45,0xe3,0x81,0x4b,0xcd,0x54,0x85,0x1e,0xaa,0xff,0xba,0x94,0xb9,0x5c, -0xaa,0x22,0x53,0xd7,0x4b,0x69,0x82,0x4d,0x7b,0xb9,0x92,0x84,0x59,0x95,0x15,0xcf,0x47,0x95,0x52,0xe2, -0x1d,0xa8,0xf4,0xc6,0x84,0x7e,0xa4,0xe9,0xe7,0xb9,0x70,0xaa,0x1d,0x68,0xda,0x76,0xbf,0x72,0x4c,0x1e, -0x7e,0x34,0x4b,0x51,0x49,0x36,0x2d,0x5e,0xf6,0xda,0xdf,0x0b,0x2f,0x7c,0x41,0xae,0x7c,0x42,0x43,0x5a, -0x5f,0x6f,0x93,0xc5,0x6f,0xa3,0xc5,0x34,0x6a,0x3b,0xad,0x44,0x3e,0xac,0xd0,0x94,0x93,0x22,0x45,0x1e, -0xd3,0xc8,0x17,0xdf,0x81,0xfa,0x65,0xc6,0x67,0xc4,0x71,0xfe,0x57,0x9e,0x8b,0x41,0x91,0x85,0x8a,0xa4, -0x40,0xff,0x18,0x38,0x27,0xaf,0x5f,0xbd,0x7a,0x76,0x72,0xf6,0xec,0x47,0xa7,0xe7,0xbc,0x7a,0x7d,0xd6, -0x28,0xbe,0xa1,0xa2,0x59,0x3e,0x2f,0xd5,0xa3,0x52,0x02,0xed,0xf7,0xc0,0x79,0xf7,0x8f,0x57,0x27,0x0f, -0x65,0x15,0xe2,0x03,0xfd,0xe1,0xce,0xd1,0xf9,0x31,0x2f,0x69,0x32,0x93,0xd1,0xa6,0x16,0x4d,0xc9,0x2c, -0x88,0x1f,0x3c,0x86,0xcb,0x72,0x91,0x1e,0xef,0x3f,0xee,0x30,0x81,0x47,0x2b,0xf2,0xa6,0x90,0x77,0xf0, -0xc8,0xcc,0x3b,0x78,0xc4,0x79,0x8b,0x20,0xee,0x53,0x50,0xb5,0x45,0xcb,0x19,0xc1,0xe6,0x2d,0x95,0xa9, -0xa7,0xde,0x01,0xf0,0x29,0x13,0x2d,0x65,0x44,0x29,0xd7,0x5a,0x4a,0x46,0x29,0x99,0x73,0x87,0x15,0x5d, -0x96,0xb4,0x84,0xe0,0x1c,0x68,0x39,0xe7,0x3c,0xc6,0x3b,0xcd,0x4b,0xc5,0x41,0x08,0xb6,0x8f,0xc0,0x71, -0x99,0x57,0xa1,0x35,0x58,0x02,0x9d,0x07,0x97,0xe2,0x8c,0x9c,0xa7,0x11,0xc5,0x8c,0x81,0xdb,0x7b,0x91, -0x86,0x71,0xe2,0x28,0xd1,0x98,0x22,0x97,0xbc,0x63,0xcc,0x5b,0xd8,0xb9,0xd6,0x95,0x5b,0xe0,0xa8,0x4b, -0xad,0x54,0xb3,0x32,0x74,0xae,0x6a,0x7a,0x20,0x6a,0x51,0x7b,0x93,0xf4,0x8d,0x5b,0xd2,0x1a,0xbe,0x34, -0x15,0x7d,0x2f,0xcb,0x3a,0x80,0x54,0xb6,0xe6,0x15,0xae,0xaa,0x3c,0x5c,0xa9,0x0d,0x9b,0xff,0x40,0x31, -0x6c,0x19,0x7a,0x3b,0x82,0x70,0xf9,0x82,0x06,0xa4,0x1f,0x77,0xab,0x4b,0xa7,0x69,0x79,0x4b,0x96,0x6d, -0x42,0xd1,0x73,0x31,0x49,0xf1,0x52,0xda,0x96,0xf5,0x81,0x02,0x85,0x3e,0x74,0x5a,0x93,0x96,0x63,0xd3, -0x76,0xc4,0x82,0x68,0x29,0x56,0xf7,0xe4,0xa8,0x82,0xf4,0x16,0x4d,0xf9,0xb8,0x3d,0xf2,0x20,0x8f,0x03, -0xfd,0x6d,0xc5,0x5b,0x06,0x9c,0x09,0x15,0xf6,0xf5,0xbb,0xc3,0xd2,0x72,0x77,0x88,0xe8,0xe1,0xd2,0x98, -0x7a,0x11,0x8e,0xaa,0x37,0xe6,0xa3,0x65,0xf9,0x81,0x1d,0xa5,0x17,0xbd,0xd7,0x65,0x8b,0x26,0x05,0x80, -0x17,0x9d,0x3c,0xa1,0xa3,0x53,0x48,0x2b,0x26,0x92,0x2b,0xbd,0x0e,0x44,0x07,0x39,0x3a,0x04,0x7a,0xd4, -0xbe,0x09,0xe0,0xde,0x71,0x3d,0x90,0xe9,0xc4,0xb1,0xb5,0xe4,0xd7,0x02,0x5a,0xc8,0x7a,0x25,0xab,0x8d, -0x6b,0x62,0x12,0x35,0x54,0x55,0xfe,0x39,0x93,0x97,0xa8,0x2b,0xf5,0xea,0x6e,0x24,0xce,0xd8,0xfe,0x30, -0xd0,0xd1,0x32,0x78,0xfc,0x61,0xb9,0x03,0x43,0x42,0xbb,0xc4,0x10,0x5b,0x1a,0x90,0x43,0xe6,0x99,0xdc, -0x75,0x09,0x52,0x1d,0xbd,0x08,0xaa,0x61,0x84,0x7e,0x1b,0xe1,0xd6,0x63,0x4e,0x9f,0xcf,0x4c,0xad,0x8f, -0xc1,0x67,0x1c,0x3a,0xb3,0xb3,0x42,0x07,0x9f,0xbb,0x0a,0x97,0x60,0x68,0xe2,0xa3,0x1f,0x8f,0xa0,0x95, -0x0f,0xda,0xed,0x97,0x52,0xf9,0x67,0x81,0xe9,0x47,0x0e,0x56,0x72,0x57,0x9a,0x45,0x3c,0x5c,0xbe,0xbc, -0x8c,0x51,0xb7,0x75,0x1e,0x17,0x23,0x5b,0x90,0x4e,0xbe,0x69,0xe1,0x40,0x0a,0xd2,0x85,0xfa,0x22,0x86, -0x08,0x30,0xb5,0xae,0xbd,0x8a,0xe6,0xa6,0xba,0x7f,0xe3,0x83,0x3d,0x2b,0x16,0x29,0xdf,0x01,0x79,0x7f, -0x9d,0x1d,0xc1,0xa0,0xa9,0xb1,0x18,0xa6,0x03,0x0e,0xe0,0x2f,0x9c,0x3c,0x5d,0x44,0x95,0x92,0xd2,0xb8, -0x99,0xc2,0xf0,0xd6,0xcb,0xfc,0x2a,0xc0,0xca,0xaa,0x43,0xcf,0x2f,0xb0,0x76,0xc8,0x19,0x7c,0x58,0xca, -0x17,0x97,0x61,0xb7,0xaf,0x29,0x54,0xed,0x68,0xa1,0x15,0x9c,0x19,0x2c,0x69,0x48,0xc1,0x88,0xbf,0x11, -0x64,0xa0,0x33,0x5c,0x14,0x03,0xb5,0x5a,0x85,0xa2,0x95,0xa7,0x29,0x14,0x05,0x08,0x49,0x99,0x4a,0x67, -0xcb,0x93,0x5a,0x5e,0x7a,0x1e,0x26,0x78,0xc5,0x95,0xbb,0xc8,0xc0,0x04,0xaf,0xb6,0x0f,0x5e,0x17,0x88, -0xd2,0x65,0x14,0xda,0xed,0x15,0x28,0x50,0x66,0x0d,0x0a,0x22,0xaf,0x8a,0x82,0xc8,0x58,0x83,0x42,0xc7, -0x35,0x18,0xca,0xd2,0x84,0x51,0x5b,0x92,0xb4,0x68,0x59,0x27,0xe5,0x50,0x23,0xe8,0x19,0x23,0x4d,0xa1, -0x93,0x24,0x9a,0x81,0xde,0x99,0x40,0x21,0x19,0x74,0x34,0x35,0x81,0x42,0x41,0xce,0xae,0x9b,0xaf,0x34, -0xa1,0x8d,0x80,0x23,0x2a,0xee,0x8e,0xf3,0x8d,0x83,0x21,0xa8,0x7b,0x9d,0x1d,0x3d,0x84,0xc7,0x24,0xcf, -0xe7,0x0e,0x87,0x07,0xa5,0xdf,0x3d,0x8c,0xe8,0x0d,0x9b,0x2c,0x86,0x30,0x27,0xde,0xab,0x0a,0x29,0x14, -0xbf,0x82,0xc8,0xbb,0xc9,0xf8,0x47,0xd1,0x06,0x01,0x79,0xce,0x4d,0x86,0x61,0x9d,0xe1,0xff,0x52,0x4a, -0xb6,0xbb,0x2b,0xb9,0xeb,0xcb,0x69,0x42,0x5e,0x57,0xc5,0x37,0xa9,0x51,0xbd,0x8f,0x86,0xef,0xe0,0x77, -0x94,0x37,0xb9,0xc6,0x42,0xb8,0x96,0xcc,0xc4,0x6d,0x73,0xa5,0x3e,0x15,0xed,0x20,0x7d,0x98,0xcc,0x3a, -0x0b,0x8d,0xfe,0xfd,0xe9,0x6e,0x20,0xea,0xf2,0x14,0xd3,0xb9,0xd3,0xf5,0xb4,0xfb,0xbc,0x32,0xe3,0xc4, -0x48,0x54,0xa2,0x6f,0xa6,0x16,0x7f,0x31,0x4a,0xe2,0xb7,0x1c,0x27,0xf1,0xc9,0x23,0xe5,0x29,0xce,0x84, -0xea,0x67,0x96,0xc3,0x93,0x26,0x39,0xc1,0x07,0x27,0xcb,0x50,0xd4,0xe5,0x20,0x1a,0xf0,0x67,0x7c,0xe3, -0x20,0x27,0x92,0x7d,0x84,0x3f,0x31,0xd2,0x6c,0x34,0xc3,0x64,0xf5,0x5a,0x28,0x7f,0xd3,0x53,0xa0,0xfc, -0xc0,0x77,0x3e,0x87,0x2f,0xb6,0xf4,0x22,0xa7,0xff,0x3e,0x9d,0x2d,0x4b,0x4a,0x2a,0xe8,0x7e,0x7c,0x44, -0x5c,0x37,0xf0,0xc4,0xd2,0xf6,0xcb,0xc1,0xbd,0x5b,0x37,0x46,0x30,0x6c,0x86,0xcb,0x4a,0x3e,0x9a,0x90, -0xab,0xd0,0x27,0x2a,0x0b,0x13,0xa6,0x15,0x58,0xa5,0x4a,0x45,0xa0,0x35,0xaa,0xc0,0x1d,0xd2,0x01,0x06, -0x76,0x94,0xa5,0xa0,0x52,0xc4,0xc6,0x06,0xc8,0x25,0x95,0x03,0xa1,0x78,0x69,0x01,0x6c,0x6b,0xf2,0x00, -0x4b,0x09,0xa9,0x21,0x6c,0x94,0x14,0x7b,0x45,0xa9,0x00,0x8f,0x71,0x09,0x50,0xee,0x39,0x15,0x58,0x91, -0x61,0x80,0x4b,0xad,0xc1,0x36,0xdb,0x34,0x97,0x0b,0xb1,0xae,0xa5,0xbd,0x84,0x54,0xee,0xab,0xb4,0x43, -0xc9,0x3c,0x2e,0x9a,0x1e,0x9d,0x2e,0xef,0xd6,0x75,0x2d,0x4b,0x04,0x62,0x35,0xfb,0x0a,0x61,0x28,0xd9, -0x00,0x85,0x83,0x13,0x6e,0x61,0x26,0xa4,0x79,0x74,0xda,0x6a,0x6e,0xb3,0xb2,0x9f,0x59,0xac,0xea,0x6f, -0x68,0xb5,0xc5,0x83,0xa6,0x12,0x58,0x79,0xaa,0xd6,0xed,0x11,0xaa,0xee,0x8c,0x2c,0x4f,0x66,0xa5,0x7b, -0xc9,0x43,0x69,0x34,0xa8,0xae,0x04,0xc5,0x5e,0xb5,0xff,0x4f,0x7f,0xef,0xc3,0x6f,0xbf,0xfd,0xb6,0x7f, -0xbe,0x8f,0xfb,0xa2,0x6b,0xce,0x42,0xb8,0x6b,0xd8,0x95,0x58,0x4c,0xa5,0x7b,0xa1,0x2b,0xa2,0xdf,0x70, -0x35,0xb5,0x11,0xd3,0xa7,0x91,0x3e,0x66,0x52,0xec,0x58,0x1c,0x3b,0x2b,0x60,0xa5,0xe5,0xa4,0x0e,0x2c, -0x4f,0x03,0xd7,0xe2,0x57,0x7b,0xc7,0x54,0xcf,0xbf,0x9a,0x55,0x24,0x3a,0x65,0x97,0x18,0xec,0xf1,0xb6, -0x6f,0x09,0xb7,0x02,0xac,0x1a,0x73,0xac,0xe8,0x94,0x7b,0x12,0x5f,0xe5,0xc8,0xab,0x4a,0x7f,0x11,0x85, -0x97,0x27,0xb8,0x54,0x96,0x63,0xdb,0x65,0x03,0xf4,0x1e,0x1b,0xa6,0xc7,0x39,0x86,0x91,0x36,0x78,0xf3, -0x56,0x26,0x04,0x00,0x5d,0xb7,0x97,0xf5,0x85,0x2d,0x24,0x3e,0x0f,0x49,0x67,0xf4,0xe2,0x47,0x9f,0xc5, -0x05,0xaa,0x9d,0x15,0x31,0x90,0x25,0x63,0x2d,0x43,0x13,0x93,0x63,0x0c,0xe7,0xf7,0x5f,0xde,0x9f,0xbc, -0xc1,0x10,0xd5,0x79,0x38,0xbb,0x94,0x56,0x65,0x42,0xed,0x38,0xe6,0xa8,0x9b,0xf0,0x43,0xbe,0x8e,0x61, -0x68,0xa0,0x72,0xf0,0xa9,0x8c,0xa2,0x88,0x65,0xf8,0x98,0x85,0x27,0x55,0xee,0xeb,0x72,0x31,0xf2,0x19, -0x36,0x73,0xbd,0x95,0x8d,0xa2,0xcf,0x2a,0xad,0xd9,0x00,0x23,0xf1,0x55,0x5a,0xd1,0x38,0xc6,0xaa,0x47, -0xbc,0xf8,0x43,0x26,0x22,0xb3,0x00,0xbf,0x8f,0xa1,0xf4,0x98,0xfc,0x18,0x4e,0x01,0x3b,0x34,0xdd,0xc1, -0x3e,0x48,0xfd,0xe3,0x60,0x8a,0x2b,0x69,0x65,0x6d,0x0e,0x45,0x0f,0x08,0xcf,0x8b,0x70,0x61,0x92,0x21, -0xc7,0xfa,0x65,0xee,0x17,0xb7,0x32,0xe6,0x7a,0xb4,0x9a,0xc7,0x5b,0xd7,0xac,0x02,0xb7,0xc6,0xc2,0xe7, -0x6a,0x06,0xfd,0x37,0xf0,0xd6,0x33,0x82,0x04,0x95,0xc5,0x99,0x19,0xac,0x29,0x5b,0xb4,0xa3,0xa7,0xa2, -0x41,0x94,0x0c,0x0e,0xe8,0xbc,0x8c,0xf2,0x49,0x32,0xda,0xe7,0xdc,0x06,0xee,0x1e,0x28,0x3e,0x01,0x96, -0xa5,0xf0,0x69,0x11,0x7d,0x8a,0xb3,0x1c,0x55,0x9e,0x85,0xe3,0xf2,0xf2,0xfa,0xe2,0xc0,0xf7,0xe9,0x5d, -0x5f,0x4a,0xec,0x2d,0x6b,0xb0,0x9f,0x6b,0x5e,0x8a,0xd0,0x98,0x25,0xa4,0xd0,0x1c,0x70,0x6c,0xa3,0x6b, -0xa4,0x38,0xba,0x41,0x33,0xa7,0x69,0xbc,0x24,0xbd,0x2a,0xf4,0x75,0x4f,0x5b,0x06,0x7e,0x48,0x3b,0x17, -0x8a,0x21,0xbf,0xc8,0x13,0xf6,0x41,0x2b,0xbf,0x7e,0xe2,0xaa,0xe0,0x6b,0x8e,0x57,0xd7,0x74,0x09,0xb7, -0x12,0x68,0x99,0x9c,0x0e,0x78,0x97,0x59,0x26,0x9c,0x92,0xa0,0x3f,0x14,0x14,0xb5,0xf7,0x9c,0x79,0x32, -0xc7,0x9b,0x04,0xba,0xdb,0xfb,0x51,0x77,0x96,0xf4,0xaf,0x05,0xb4,0x93,0x7f,0xee,0x75,0x3d,0xf9,0xaa, -0x4e,0x55,0xa4,0x22,0xa4,0x4f,0xef,0xc0,0xbb,0x4e,0x86,0x31,0xeb,0x7d,0xf1,0x2f,0x0e,0x28,0xf2,0xe8, -0x87,0x8e,0x87,0x3a,0xd3,0x70,0x68,0x90,0x21,0x15,0xf6,0x03,0x39,0xcd,0xd7,0x4c,0x6e,0x04,0xcf,0x66, -0xe1,0x9c,0xac,0xb8,0xe0,0xef,0x59,0x32,0x85,0x63,0x06,0x56,0x4a,0xcf,0xef,0x1c,0x62,0x00,0xc6,0xa7, -0x7f,0x7f,0x7e,0xf1,0xf6,0xd9,0xcf,0xc7,0x67,0xa7,0xbf,0x3e,0xbb,0x78,0x73,0xfc,0xfc,0xd9,0xc5,0xeb, -0xb7,0xa7,0xcf,0x4f,0x5f,0xe1,0xbd,0x2a,0xf7,0xc5,0x6f,0x76,0x53,0xd6,0xf1,0x28,0x34,0xd1,0x1d,0xc5, -0x82,0x04,0xca,0x9e,0x25,0xef,0x72,0x6d,0x73,0x53,0x0a,0xe5,0x29,0x9a,0x0d,0x64,0xa4,0xe6,0x8b,0x0f, -0x12,0x68,0x32,0x4f,0xca,0x1d,0x3d,0xc8,0xf8,0xc6,0xe9,0xd3,0x37,0x92,0xbe,0xc7,0x9b,0x88,0x66,0xe4, -0x7b,0x70,0x78,0xb8,0x07,0x67,0x06,0x6e,0x60,0xca,0x46,0x97,0xec,0x01,0xa5,0x73,0x1d,0x0e,0x4e,0xd7, -0xc1,0x88,0x94,0x7d,0xde,0xc4,0x2a,0xa5,0xc7,0xd5,0xd2,0x5a,0xdc,0x93,0x8c,0x4a,0x67,0xae,0x30,0x6b, -0xa8,0x94,0x1e,0x56,0x4b,0x87,0x45,0xe9,0x90,0x4a,0xa3,0xf2,0x50,0x2b,0x88,0x61,0x92,0x86,0xfd,0x61, -0x1a,0x85,0x1f,0xfb,0xb2,0x8b,0x61,0xb9,0x8f,0xe1,0x7f,0x71,0x27,0xc5,0x79,0x50,0x29,0x1d,0x56,0x4b, -0x17,0x81,0x10,0x9b,0x09,0x95,0x4e,0x0a,0x12,0xb5,0x12,0x9d,0x48,0xf8,0xa2,0x83,0x34,0x82,0xbf,0x4d, -0xa7,0x65,0xa1,0x0a,0x29,0x75,0x58,0xfa,0x6b,0x4f,0x1f,0x42,0xba,0xeb,0x94,0x1a,0x78,0xa0,0xb5,0xc0, -0x5a,0x21,0x69,0xcb,0x79,0xe0,0xc9,0x8f,0xb1,0xfe,0x31,0x84,0x8f,0x4a,0x05,0xa1,0xac,0x20,0xfc,0x5a, -0x38,0x7a,0xf4,0x42,0x68,0xc1,0x35,0x7c,0xa0,0xb7,0xb5,0x09,0xb6,0xea,0x23,0xac,0xa0,0x8e,0x2f,0x59, -0x58,0x1b,0xfc,0x85,0xca,0x84,0xf2,0x8c,0x68,0x3c,0x13,0x7f,0x97,0x65,0x24,0x00,0xf8,0x81,0x56,0x8a, -0xeb,0x9e,0xe8,0x0d,0x65,0xfa,0xc7,0xd2,0xd6,0x6a,0x28,0x2b,0x08,0x57,0xb5,0x6b,0x27,0x02,0x96,0x7a, -0xa0,0x97,0xdf,0x04,0x83,0x95,0x44,0x18,0x8a,0xda,0x70,0xfc,0x37,0x22,0xc0,0xf0,0x81,0x56,0xe2,0x3e, -0x04,0x18,0x4a,0x02,0xd0,0x28,0x6e,0xd5,0xf9,0xa1,0xea,0xfc,0xf0,0x9e,0x9d,0x97,0xb6,0x6a,0x29,0x6e, -0xcc,0x70,0x2f,0x3c,0x4b,0xe8,0xdc,0xab,0xf2,0xf0,0x18,0xe6,0x2b,0xb8,0x0d,0x7b,0xdd,0xbb,0x3e,0xd9, -0x76,0xa3,0x5f,0x32,0x7c,0x6c,0xc3,0x7d,0x7a,0xff,0x9f,0xdf,0x7c,0xe8,0xb4,0xff,0x16,0xb6,0xaf,0xce, -0x6f,0xbf,0xbb,0xfb,0x76,0x3f,0xa6,0xe8,0x28,0xd5,0xbc,0x47,0x94,0x47,0x4f,0x6e,0x71,0xf6,0x2a,0x7c, -0xd5,0x8c,0xfd,0x34,0xe8,0x7e,0xbf,0xa7,0xbd,0xde,0x65,0x8b,0x21,0x60,0xd1,0xec,0x7a,0x5d,0xd7,0x83, -0xfd,0x61,0x1f,0x56,0x81,0x5b,0x98,0x73,0x69,0x05,0xc7,0xf6,0x82,0x07,0x6b,0x0b,0x0e,0xed,0x05,0xbf, -0xab,0x2d,0x78,0x88,0xb2,0x15,0xb9,0x45,0xc9,0x5a,0x42,0x7b,0x2d,0x8f,0xac,0xb5,0x68,0x26,0xf1,0x26, -0xd9,0x2a,0x54,0xab,0x05,0xd8,0x9c,0x74,0x9d,0xfb,0x92,0x6e,0x3d,0xcd,0x6b,0x48,0x57,0x4f,0xf3,0x47, -0x5b,0x90,0xce,0x3e,0x00,0xb5,0xa4,0x2b,0x66,0xd5,0xe3,0x1a,0xda,0x15,0x10,0x3f,0xd8,0x88,0x67,0x23, -0xc0,0xc1,0x5a,0xca,0xd9,0xf0,0x5e,0x57,0x6a,0x68,0x29,0x75,0x58,0x5b,0xea,0x6f,0x76,0x9a,0x55,0xab, -0xf8,0xde,0x5a,0xc5,0xfa,0xb9,0x56,0x47,0xaf,0x6d,0xc9,0xd5,0xb9,0x17,0xb9,0x0e,0xee,0x45,0xae,0x47, -0xb5,0xa5,0x7e,0xd8,0x94,0x5c,0x8f,0xb7,0x23,0x17,0x1e,0xaa,0xbf,0x65,0xe8,0x0e,0x2b,0xdb,0x6b,0x22, -0x69,0x7e,0xf3,0xcf,0x5b,0x0f,0xfe,0xf8,0xd0,0xe9,0x9e,0x0f,0x7e,0xf3,0x07,0x98,0x72,0xbe,0xe7,0x42, -0xa6,0xf7,0xe7,0x03,0xfc,0xe6,0xda,0x47,0x0c,0x70,0xfc,0x8b,0x50,0x64,0x0c,0x68,0x4a,0xa4,0x41,0x09, -0x8d,0x70,0x1f,0x23,0xbc,0x07,0x92,0xd0,0xe4,0x93,0xa8,0x90,0x45,0x37,0x1d,0xb7,0xd5,0xf5,0xb4,0x04, -0x0f,0xfd,0xbe,0x3b,0x0f,0x90,0xff,0x94,0x42,0x07,0xa5,0x76,0xd0,0xb5,0xce,0x3a,0x8e,0x96,0x9b,0xbb, -0xa8,0x0f,0x63,0x19,0x39,0xcb,0x1c,0xcd,0x2d,0x13,0xa5,0x16,0x43,0xaf,0x8a,0xa1,0x57,0xce,0xde,0x18, -0xe5,0xf1,0x56,0x28,0x8f,0xd7,0xa1,0x9c,0x0e,0x6a,0x91,0xae,0xe2,0x48,0xbd,0x40,0x4f,0x61,0xa7,0x3a, -0xad,0x7b,0x66,0x0d,0xe5,0xfc,0x6a,0x21,0x77,0xf3,0x01,0x1a,0x6e,0xd5,0xdb,0xe1,0xea,0xde,0xa6,0xae, -0x65,0x94,0xbe,0x2a,0xba,0xe1,0x56,0xe8,0x96,0xa0,0x4b,0x90,0xb7,0x62,0xcf,0x08,0xb4,0xf5,0x88,0x77, -0xd0,0xff,0xac,0x3d,0x63,0x77,0xd7,0x82,0xe3,0x5f,0xba,0x67,0xd8,0x30,0xf8,0x4f,0xdb,0x59,0xad,0x38, -0xfe,0xb5,0x3b,0xab,0xb1,0x10,0xfe,0xba,0x1d,0x76,0xb2,0xd5,0x8a,0x28,0x43,0x03,0xb3,0xf6,0x7f,0xb1, -0xc7,0x66,0x5b,0x21,0x9d,0xd5,0x2d,0xe3,0xff,0x8a,0x1d,0x76,0xb9,0x55,0x5f,0x97,0xab,0xfa,0xfa,0xdf, -0xb3,0xbf,0x4a,0x8d,0x5d,0xe4,0x49,0x61,0xbf,0x3a,0x4b,0xde,0x8e,0x87,0x86,0xa8,0x10,0x83,0xce,0x8a, -0x47,0x84,0x27,0x41,0x77,0xff,0x31,0xb0,0x9b,0x47,0xc1,0xe1,0xfe,0xe3,0x41,0xb7,0x17,0x3d,0xe9,0xee, -0x7f,0x37,0xe8,0xb6,0x1f,0xef,0x35,0xa3,0x36,0x64,0xc1,0xe8,0x1c,0x3d,0x82,0x1c,0xfa,0x7e,0x84,0xdf, -0x1d,0x2f,0x0b,0x00,0x1c,0xf2,0xc8,0xe3,0xab,0x7f,0x28,0x4a,0x21,0x4c,0x04,0xbf,0x10,0x5a,0x94,0xf7, -0x0f,0x11,0x3c,0x44,0x70,0xff,0x90,0xa0,0x45,0x23,0x47,0x07,0x5c,0x1a,0x0a,0x13,0xe0,0x01,0x37,0x74, -0x58,0x14,0x3d,0xe4,0xa6,0x92,0xa0,0x19,0xb7,0x9a,0xdd,0x76,0xec,0xee,0xc1,0xff,0xa1,0x97,0x7b,0xa9, -0x37,0x0b,0x9a,0x59,0x8b,0xc3,0x12,0xa9,0xb4,0x69,0xd0,0x0c,0x31,0x2d,0x2c,0xd2,0xc4,0x13,0xca,0x6d, -0xda,0x4b,0xbc,0x71,0x6f,0xe6,0x0d,0x7b,0xd3,0x3b,0xa4,0x08,0xdc,0xfa,0xce,0x92,0x17,0xd9,0xd2,0x4e, -0x11,0xf2,0x97,0x2e,0x04,0x6f,0x18,0xb8,0x98,0xf3,0xa0,0x4d,0x4e,0x89,0x25,0x34,0xb4,0x98,0xb4,0x67, -0xf2,0x99,0x26,0x0b,0x3a,0x3b,0x41,0x32,0x98,0xee,0x27,0x80,0x73,0x8c,0x2a,0x55,0xd3,0x41,0xa7,0x17, -0x05,0x90,0xd6,0x7c,0xdc,0x6a,0xe6,0xed,0xd4,0xdd,0x9f,0xba,0x0f,0x1e,0xf7,0x72,0x4c,0x3a,0x68,0x35, -0xd3,0x76,0x04,0x29,0xbd,0x14,0x3f,0x1f,0xb5,0xa0,0xbf,0x39,0x7e,0x42,0xd9,0xfd,0xe0,0x31,0x10,0x2c, -0xf1,0x6e,0x27,0x3d,0xc0,0xa5,0x97,0x79,0xcb,0x5e,0x48,0x68,0x5b,0xdf,0xb4,0x28,0x76,0x38,0xbb,0xd1, -0x46,0x91,0x79,0x90,0xca,0x18,0x27,0x28,0x83,0x80,0x2a,0x60,0xac,0xe0,0xdf,0xb2,0xd7,0xf5,0x52,0xf8, -0x37,0x86,0x7f,0x43,0xf8,0x87,0x52,0x08,0x06,0x94,0x5a,0xd9,0xcd,0xa2,0x0e,0x56,0x01,0x93,0x41,0x11, -0x58,0x90,0x0d,0x93,0x5e,0xb8,0x34,0xdf,0xe9,0x78,0xb7,0x88,0x8d,0x94,0xe7,0xbb,0xaa,0x1e,0x21,0xf3, -0xc6,0x90,0xa4,0x7c,0x1a,0xe8,0x15,0x08,0xa5,0x2c,0x7c,0x62,0xb2,0x25,0x07,0xce,0xcd,0x72,0xee,0xb4, -0xcc,0x3c,0x7e,0x28,0x30,0xfd,0x71,0x06,0x9d,0x01,0xfc,0xed,0x39,0x2a,0xf6,0x11,0xbe,0xe9,0xa3,0x4f, -0x3a,0x83,0x3e,0xfe,0x4d,0x3c,0x1a,0x47,0x39,0xc7,0x5d,0x32,0x73,0xd0,0x41,0xce,0x34,0xfc,0x6c,0xcb, -0xc2,0xaa,0x4a,0x91,0xfc,0xba,0x3b,0x41,0x15,0x06,0xdd,0x9d,0x9c,0xc2,0x5f,0x20,0x7c,0x6d,0x1e,0x9a, -0x0f,0x09,0x03,0xb2,0xe6,0x43,0x2d,0x10,0x21,0xbf,0x98,0xb5,0x05,0x16,0x4e,0x83,0x02,0x55,0x07,0xce, -0x28,0xce,0xe6,0xf0,0xdd,0x6b,0xa0,0x86,0x52,0xdf,0x11,0x31,0x09,0x1f,0xba,0xfd,0xd4,0x50,0x4b,0xf0, -0xd9,0xfa,0x5c,0xf5,0xe2,0x82,0x32,0xdc,0x9a,0x2e,0xa6,0xe8,0xd8,0x08,0x1d,0x3f,0x46,0x4d,0x07,0x63, -0x6b,0xab,0x10,0x87,0xb0,0x93,0xf5,0x79,0xf5,0x9b,0x05,0x01,0x9c,0xde,0x4f,0x50,0xa7,0xe4,0xef,0xe9, -0xb4,0x79,0x00,0xdb,0x4f,0x1f,0x35,0x5d,0xa2,0x70,0x54,0x14,0x7e,0xf8,0x84,0x90,0x6e,0x90,0x2b,0x17, -0x27,0x87,0x79,0xb1,0x8f,0xef,0x0b,0x47,0x3e,0x77,0xed,0x86,0xaa,0x68,0xdc,0xa2,0x5e,0xc0,0x98,0x24, -0xb1,0xbd,0xc6,0x02,0x2a,0x7b,0xd8,0x8a,0x5b,0x8e,0x0b,0x1d,0x6c,0xa7,0xd1,0x3c,0x0a,0xf3,0xc6,0x25, -0xb9,0x07,0x16,0x7f,0xfa,0x77,0x4f,0xf6,0xa9,0x5a,0x8c,0x50,0x4a,0xca,0x35,0xd7,0x53,0xf1,0x18,0x2d, -0x22,0xe3,0x54,0x1f,0x9e,0x34,0x7a,0x20,0xf8,0x85,0x00,0x2c,0x97,0x97,0x11,0x75,0xee,0x5d,0x81,0x0a, -0xe2,0xb3,0x61,0x0d,0x08,0x6a,0x45,0xe2,0x1e,0x75,0xb0,0x9a,0x13,0xd7,0xc1,0x0e,0x08,0x56,0x56,0xc0, -0xe0,0x17,0x0c,0xe9,0x96,0xb7,0x0d,0x9f,0x95,0xe3,0xdf,0xf3,0xe2,0xa8,0xbc,0x8b,0x47,0x66,0xc8,0x4c, -0x39,0x9c,0x04,0xfd,0xf0,0xc8,0x96,0x85,0x98,0xd4,0xe7,0xbc,0xe6,0x79,0x28,0x23,0x6c,0x52,0xac,0x55, -0x1b,0xdc,0xc9,0x22,0xcd,0x92,0x14,0xc1,0x28,0xe2,0xaa,0x80,0xae,0x56,0xfa,0x62,0x11,0x35,0xf8,0x27, -0xef,0x1a,0x6d,0x8c,0x7c,0x3b,0x8f,0xb0,0xe4,0x65,0x38,0x5b,0x86,0x59,0x15,0xfe,0x1d,0x01,0x1a,0xa5, -0x1e,0x36,0x28,0xc0,0x4e,0xf0,0xb0,0xfb,0xb0,0x31,0x89,0x28,0x56,0xe8,0xc3,0xc3,0xce,0xc3,0x06,0x1b, -0xf9,0x3c,0x84,0x42,0x88,0x09,0x57,0x68,0xc5,0x19,0x20,0x18,0x63,0x59,0xed,0xe5,0x86,0xf8,0xbf,0x83, -0x49,0xbf,0x0d,0xfe,0x00,0xbf,0x3d,0xfe,0xef,0xd0,0xb7,0x3c,0x3b,0x73,0x5d,0xdd,0x0d,0x00,0xbc,0x5f, -0x37,0xe0,0xbc,0xd8,0xaa,0x1b,0x00,0xbf,0x7d,0x37,0xe8,0x50,0x5a,0xd3,0x03,0x80,0xb9,0x5f,0x0f,0xde, -0x46,0xa3,0xad,0x7a,0x00,0xf0,0xdb,0xf7,0x00,0x0a,0xad,0xc1,0x1f,0x20,0xee,0x87,0xff,0xf3,0x14,0xbd, -0xfb,0x6d,0xd3,0x03,0x2a,0xb1,0x7d,0x1f,0xa8,0xd8,0x9a,0x5e,0x10,0xcc,0xfd,0xfa,0xf1,0x74,0xba,0xe5, -0x8a,0xc6,0x02,0xdb,0xf7,0xe2,0xe9,0xfa,0xa9,0x84,0x20,0xf7,0xeb,0xc3,0xf1,0x74,0x3e,0x09,0xb7,0xea, -0x04,0x95,0xd8,0xbe,0x17,0x54,0x6c,0x4d,0x37,0x08,0xe6,0x7e,0xfd,0x78,0xc3,0x8a,0x18,0x75,0x48,0x8b, -0xec,0xa7,0xc9,0x27,0x1b,0x9a,0xdd,0x62,0xfb,0x21,0xfd,0x2d,0x58,0x5f,0x74,0xec,0xe8,0xe8,0x72,0xc3, -0x22,0xd6,0x72,0xe1,0x42,0x50,0xd8,0x1c,0xeb,0xe7,0x81,0xd7,0xf0,0x6d,0xf4,0x2c,0x92,0xb9,0x4f,0x25, -0x30,0xa9,0x71,0x69,0x0b,0x93,0xcc,0xd1,0x61,0xdb,0xd7,0xc9,0xbf,0xdb,0xa8,0x5d,0xd2,0x96,0x5a,0x66, -0xac,0x10,0x2e,0xb3,0x6f,0xa2,0xe1,0xc7,0x38,0x5f,0x01,0xb1,0xbe,0x2c,0x1d,0xf3,0x6d,0x8c,0x5f,0xc3, -0xa1,0x2a,0x18,0xc6,0x13,0xb7,0x38,0xf4,0xf2,0xfb,0x29,0x47,0x3d,0x52,0xcb,0x21,0x5e,0xd1,0x25,0x24, -0x25,0xc1,0xb4,0xb8,0x81,0xa0,0x57,0x4a,0x4b,0x39,0x93,0x76,0xc6,0x65,0x00,0x13,0x2e,0x54,0x59,0x59, -0x59,0x11,0xe5,0xf0,0x6b,0xd4,0xb6,0x39,0x6a,0x3c,0x2f,0x2b,0x55,0x72,0xf2,0x17,0xa1,0xb9,0x65,0xcd, -0x9b,0xa0,0x2c,0xdd,0x2f,0x14,0x55,0x72,0xca,0x3d,0xf1,0xdc,0xbc,0xba,0x8d,0x90,0xbb,0xac,0x74,0x98, -0xab,0xfb,0x22,0x5a,0x6e,0x55,0x2b,0x73,0x16,0xe5,0xfb,0x65,0x89,0x81,0xb0,0x28,0xb2,0x47,0xfb,0x07, -0x5e,0x1a,0xe4,0xc0,0x22,0x2b,0xeb,0x6a,0xbe,0x94,0x0a,0x07,0xac,0xe8,0x01,0x12,0xf7,0x0b,0xd4,0x5f, -0xf4,0x79,0xa3,0x89,0xbc,0xd8,0x17,0x1b,0x4d,0xa4,0xcc,0x74,0x50,0x33,0x93,0xbc,0x96,0xd0,0x92,0x6a, -0x3a,0x07,0x23,0x47,0x39,0x41,0x22,0xef,0x47,0x12,0x30,0x81,0xb4,0x04,0xd2,0x12,0x69,0x02,0x25,0x18, -0xf9,0xec,0x5f,0x69,0xce,0x61,0x0d,0xe6,0xc9,0x4d,0x13,0x98,0x12,0x34,0x03,0x54,0xdf,0x21,0x7d,0x0b, -0xb3,0xbf,0xd9,0x51,0xde,0x3a,0x70,0xa5,0x6e,0x5f,0x13,0x81,0x03,0xe0,0x43,0xc3,0x27,0xe9,0xe0,0x6f, -0x9d,0xde,0xc1,0xf7,0x9d,0x1e,0xc7,0x20,0xcc,0xc3,0x59,0x13,0xf8,0xfa,0xd0,0xdd,0x47,0x10,0xd7,0xdd, -0xa7,0xe4,0x37,0xa7,0x7b,0xdd,0x1f,0x3a,0x6e,0xab,0x99,0x00,0x3c,0xfc,0xea,0xc1,0x6f,0x94,0xfb,0x3d, -0x40,0xb3,0xe5,0x51,0x30,0xdb,0xcf,0xbd,0x49,0xd0,0x54,0x51,0x0c,0xa7,0x94,0xd9,0x12,0x00,0x4f,0xba, -0x07,0x9d,0x41,0xb7,0x37,0x3d,0x3a,0x78,0xd4,0x19,0x34,0xe1,0xa3,0x5d,0x00,0xb6,0x49,0x7a,0xb8,0xff, -0xb8,0xd3,0x9b,0x12,0x18,0x65,0x4f,0x29,0xa1,0xe3,0x2d,0x02,0x0d,0x10,0x32,0xdc,0x27,0x8f,0xb1,0xa2, -0x72,0xa2,0x2a,0x57,0xca,0x10,0xb5,0x5c,0xea,0xb5,0x00,0x0a,0xd5,0x5a,0x28,0xd1,0x56,0x0b,0x66,0x88, -0x5a,0xe6,0x65,0x2d,0xa6,0xe6,0x04,0x25,0x35,0x13,0x92,0xd4,0x8c,0x5c,0xe0,0xe4,0x4f,0x2a,0x10,0x0b, -0x84,0x58,0x14,0x10,0x57,0x15,0x88,0x4b,0x84,0xb8,0x54,0x10,0x7d,0xf2,0xb6,0x3b,0xe5,0x28,0x78,0x42, -0xfd,0x68,0x4e,0x8a,0x1f,0x27,0xf4,0xff,0x2b,0x54,0xfe,0xf0,0x18,0xe8,0x2d,0x6a,0x13,0x27,0x5e,0xe8, -0xe1,0x8b,0xfd,0x9d,0x92,0x96,0xf9,0x79,0x42,0x13,0xf7,0xed,0xcf,0x55,0x81,0x82,0x16,0x09,0x52,0x48, -0x44,0x2c,0x02,0x04,0x3d,0x52,0x2b,0x0a,0x63,0x56,0x82,0xd4,0x8b,0x28,0x0a,0x18,0x16,0xe3,0xac,0x04, -0x41,0x51,0x23,0x5d,0x96,0x57,0x83,0x15,0xf2,0x19,0x4d,0x76,0x24,0x9e,0x23,0x4b,0xb2,0x9d,0xd4,0x14, -0xfd,0xf8,0x9a,0x3e,0xa3,0x5a,0x55,0xe4,0x87,0x4b,0x13,0x02,0x69,0xd2,0xa3,0x49,0x98,0x1d,0xc3,0x39, -0x1c,0x0f,0x17,0x79,0x24,0x1c,0x42,0xdc,0x5c,0xce,0xdb,0xa8,0x4f,0xb7,0xbb,0xab,0x34,0x83,0xd3,0x0f, -0xf1,0xf9,0xee,0x6e,0x13,0xff,0x04,0x5a,0x61,0xa0,0x48,0x5d,0x61,0x4f,0x1a,0x98,0x61,0x99,0x01,0x15, -0xdc,0xe9,0xf4,0x9c,0xab,0x10,0x6d,0x46,0xcc,0x0a,0x77,0xba,0x6e,0x61,0x4c,0x48,0xa8,0x92,0xe8,0x56, -0x29,0xc9,0xea,0xdd,0x03,0x78,0xe9,0xb0,0x27,0xae,0xd5,0xe1,0x8e,0x95,0x0e,0x77,0xbf,0x26,0x8a,0xb7, -0x50,0x25,0xce,0xce,0x07,0xc6,0x17,0xe1,0x23,0x22,0x8c,0x17,0x0d,0x12,0xb2,0x72,0xda,0x71,0xb8,0xc1, -0xfa,0x89,0x54,0x91,0x49,0x55,0x85,0x4e,0x4d,0xd7,0x43,0x41,0x15,0xc7,0xa3,0x95,0xa2,0x29,0xed,0x4b, -0x17,0x46,0x15,0xc4,0x26,0x3d,0x6f,0x98,0x33,0x7d,0x67,0x38,0x4d,0x2e,0xc9,0xd8,0x5c,0x1f,0x76,0x56, -0x99,0x15,0x41,0x73,0xc5,0x64,0xad,0x97,0x26,0x90,0x0b,0xa4,0x48,0x07,0x86,0x84,0x1a,0x25,0x71,0x52, -0x20,0x87,0x5c,0x48,0x89,0xd2,0xfc,0xf8,0x2a,0x17,0xea,0xe5,0x12,0x2d,0x27,0x9e,0x4d,0xe3,0x19,0x0d, -0x2a,0xdf,0xae,0x84,0x74,0xcc,0x71,0x07,0xb1,0x99,0x20,0x41,0xdb,0xdc,0x03,0xb7,0x57,0xce,0x2f,0x57, -0x80,0xcd,0x0a,0x31,0x96,0xde,0x62,0x2a,0x1d,0x1f,0xcb,0x29,0x92,0x96,0x9d,0x87,0x62,0xd3,0x65,0x7f, -0xa2,0x55,0x20,0x44,0xa0,0x0c,0x25,0xc3,0xcb,0x0a,0x1b,0x62,0x45,0x2e,0x91,0x38,0x4a,0xc3,0x1b,0x66, -0x06,0xb2,0xa6,0x0a,0x45,0xcb,0xe6,0x3e,0x32,0x19,0x91,0xc6,0x53,0xfc,0x0a,0x4e,0xcc,0x6c,0x8d,0xf8, -0x07,0x2b,0xbf,0x20,0xc0,0x0b,0xa2,0x89,0x2c,0x3b,0x9c,0x2e,0xd2,0x4d,0x8a,0x22,0x9c,0x28,0xe9,0xf6, -0xc4,0xfb,0xac,0x4d,0xb4,0x8a,0x72,0x5c,0x9b,0xc4,0x75,0xfd,0x0c,0xb1,0x94,0x42,0x24,0xc5,0x00,0x54, -0x44,0x95,0xb1,0xec,0xc1,0xaa,0x8b,0x51,0xa5,0x1b,0x0a,0xf8,0x82,0x34,0xbe,0xa5,0xb0,0xd8,0x8a,0x24, -0x27,0x8a,0x9b,0xd2,0x7a,0x1a,0xd3,0x94,0x11,0x24,0xe6,0xca,0x45,0xd1,0xb5,0x24,0xe6,0x92,0x44,0x61, -0x89,0x15,0x97,0xfc,0x18,0x7d,0x5e,0x23,0xdf,0xe4,0xa2,0x04,0xa7,0xb8,0x09,0x32,0x8f,0xd9,0xa0,0x14, -0x03,0xc2,0xb2,0x2a,0x5b,0x62,0x18,0xcb,0x9d,0x8e,0x1a,0xb1,0xda,0xa5,0x0b,0x94,0x66,0x15,0xa2,0x74, -0x36,0xf0,0x01,0x25,0xe2,0xbe,0xf6,0x2a,0x76,0x31,0x55,0x58,0x29,0xff,0x37,0xdf,0x1d,0x36,0x6e,0xc2, -0xcc,0x52,0x96,0x02,0x83,0x54,0x78,0xc3,0x3d,0xa6,0xc5,0x87,0x4e,0xe1,0x93,0xd9,0x14,0x66,0x51,0x4f, -0xae,0x51,0x95,0x84,0x8e,0x67,0x2a,0x72,0xd1,0x62,0xbf,0x1d,0x45,0xd0,0x87,0xe4,0x73,0x59,0x38,0x9a, -0x97,0xf7,0xb6,0xd2,0x56,0xba,0x72,0x0f,0xa5,0xb5,0x32,0x8c,0xae,0xd0,0x17,0xbd,0xbe,0xeb,0xe4,0xca, -0x85,0x2f,0x0c,0x29,0x7b,0xff,0xa0,0xc1,0xbd,0xba,0xaa,0x9d,0x87,0x2a,0xdf,0x3e,0xd9,0x54,0x76,0xcd, -0x8c,0x52,0xf9,0x75,0x93,0x07,0x01,0xec,0x9b,0x36,0x6e,0x05,0x2e,0xfa,0x43,0x8e,0xf2,0x68,0xcd,0x99, -0x65,0xec,0x74,0x1b,0x50,0x52,0x27,0x19,0xec,0x11,0x3b,0xdd,0xbe,0x74,0x27,0x45,0x32,0x08,0xd8,0xe5, -0x0d,0x51,0x34,0x7a,0x19,0x91,0xd4,0x4e,0x15,0x89,0xf3,0x22,0xac,0xb9,0x00,0x17,0x67,0x82,0xa7,0xe5, -0xd0,0x71,0xc0,0x81,0xce,0x3d,0x61,0x40,0x1c,0xcf,0x66,0x51,0x4a,0xc6,0x1c,0x4f,0xa0,0x36,0xcd,0xb6, -0x63,0x77,0x57,0xb4,0xb2,0xa3,0xb5,0x22,0x21,0xc8,0x48,0x00,0xae,0x4b,0xd5,0x56,0x39,0x9f,0x9e,0xa7, -0xee,0x23,0xdb,0x90,0x82,0x16,0xe5,0x8b,0x5f,0x6b,0x00,0x12,0x46,0xd1,0x4c,0x0b,0xdb,0x96,0xd1,0xd5, -0x46,0xbe,0xa1,0x31,0x7d,0x43,0x3e,0xd3,0xa5,0x01,0x88,0xe5,0xad,0x8d,0x2c,0xac,0x48,0xff,0xf9,0xc6, -0xe9,0x85,0x81,0x15,0x4d,0x68,0x44,0xd7,0x93,0xb6,0xc1,0xbd,0x58,0x44,0x26,0x54,0x66,0x83,0x7a,0x17, -0xe6,0x26,0xd4,0xd2,0x06,0xf5,0x6b,0x58,0x6a,0x31,0xb5,0x41,0xbd,0x25,0x47,0xe2,0x1a,0xd4,0xd8,0x06, -0x45,0xf2,0x48,0x13,0x6e,0x68,0x83,0x43,0x91,0x9f,0x09,0x16,0xda,0xc0,0x48,0xa4,0x66,0xc2,0xcd,0x6d, -0x70,0x6a,0xdc,0xee,0x44,0x7c,0x6a,0xb4,0xe5,0x28,0x5c,0xe4,0x19,0x53,0x3e,0x14,0xab,0x5d,0xac,0xff, -0xd2,0xf0,0xb2,0x25,0x77,0x12,0x1c,0x76,0xf6,0x52,0x5f,0x18,0x26,0xf5,0x4b,0xcd,0x95,0x44,0x5e,0xcc, -0x1e,0x3b,0x68,0x64,0x26,0x22,0x89,0x7c,0xe1,0xdc,0x9b,0x25,0xc0,0x53,0xfb,0x6a,0xc2,0x21,0x9b,0xe0, -0x17,0xe6,0x57,0xbb,0xbb,0x3b,0xb1,0x64,0x87,0x3b,0xfd,0x19,0xdd,0xb1,0x6e,0x89,0x59,0x47,0x5b,0x2b, -0x46,0x06,0x7e,0xa1,0xd1,0x7f,0xc9,0x74,0x51,0x57,0x3c,0xc0,0x57,0xc8,0x69,0x4b,0xd7,0x61,0x10,0xb7, -0xb7,0x6b,0x8a,0xa9,0xde,0x46,0xab,0x27,0xc7,0x2d,0xec,0xed,0xe7,0x9f,0xc8,0xa8,0xdf,0x6d,0xd5,0x96, -0x20,0x57,0x5b,0xd6,0x22,0x70,0x85,0xc0,0x78,0x60,0xb4,0xb0,0xc9,0x58,0x35,0xd7,0x91,0x9e,0xb6,0x10, -0xf2,0x8e,0xbd,0xbb,0xdc,0xe6,0x66,0x7f,0xee,0xa4,0x6b,0xa2,0x9a,0x85,0x52,0xa2,0x15,0x30,0xf3,0xd6, -0xb1,0xda,0x8e,0xda,0x23,0xc6,0x41,0x90,0x32,0x17,0xf2,0x0f,0xe0,0x44,0xa8,0x4b,0x8c,0x5a,0x91,0x7a, -0x87,0x6e,0x33,0x0d,0x1b,0xd6,0x05,0x20,0x71,0xc3,0x9d,0x6d,0x8f,0x8c,0xbe,0xb7,0x35,0xea,0x8d,0x36, -0xa2,0x77,0x7d,0x89,0x5a,0x7a,0x17,0x76,0xae,0x1a,0x22,0xd8,0xaf,0x49,0xc9,0x08,0xf3,0x52,0x1f,0xfe, -0xc9,0xd6,0xc3,0x3f,0xd9,0x10,0x9d,0xc9,0x06,0xe4,0x6c,0x2e,0xda,0x0a,0xbd,0x76,0xd7,0xdd,0xbb,0x74, -0xf7,0xe5,0xa7,0x9c,0x1e,0x9b,0xb1,0x6c,0xc6,0x9d,0x3e,0x28,0x39,0x07,0xd4,0x34,0x23,0xc4,0x6e,0xa0, -0xd5,0x69,0x32,0x69,0x22,0x9f,0xfc,0x96,0x95,0x2f,0x56,0xca,0x4c,0xf8,0x43,0xe7,0x9c,0xfc,0x17,0x16, -0x09,0xdd,0x73,0xbe,0x25,0xe1,0xb1,0x65,0xb7,0x0c,0xae,0x34,0x19,0x9b,0x47,0x70,0x16,0x14,0x3a,0x24, -0x5e,0x18,0x74,0x3d,0xda,0x8b,0x62,0xb9,0x17,0x79,0x33,0x48,0x82,0x85,0xef,0xa1,0x23,0x88,0x09,0x3a, -0x83,0x08,0x50,0x52,0x84,0x72,0x9e,0x6e,0x3f,0xf6,0xd1,0x8c,0x93,0x0d,0x89,0xfd,0x10,0xc0,0x4a,0x62, -0x1b,0x60,0x79,0x60,0xb2,0x56,0x53,0xc7,0xb8,0x70,0x2a,0xa9,0x43,0x17,0x2a,0x07,0x36,0x16,0xaa,0x87, -0xe3,0x0b,0x1a,0xc8,0xd0,0xc5,0x30,0xa2,0x7c,0x12,0x94,0x9f,0x0e,0x8a,0x17,0x0a,0xe1,0xae,0xeb,0x44, -0x0b,0x4b,0xa3,0xf6,0x56,0x9a,0x75,0x57,0xc1,0x89,0x10,0x60,0x56,0x64,0x88,0xfd,0xab,0x92,0x18,0x09, -0xcd,0x82,0xa6,0x24,0x41,0x1a,0xd1,0xff,0xd9,0xb8,0x68,0x46,0xd2,0xa4,0x2b,0xff,0x12,0xfd,0x8f,0x92, -0x38,0xa9,0xe3,0x75,0x48,0x9c,0xe4,0x5d,0x15,0x22,0x26,0x99,0x76,0x47,0x8e,0x89,0x8d,0x8b,0x21,0x11, -0x69,0xa7,0x3a,0xfa,0xe3,0x4a,0xbf,0xb4,0xe7,0x22,0xd1,0xb1,0xb1,0xa5,0x63,0x7f,0xfc,0x21,0xcc,0x3f, -0x97,0xc1,0xb8,0xae,0x6f,0xde,0x4d,0xb0,0x14,0x2c,0xd9,0xcf,0xc0,0x34,0x87,0xe9,0x73,0xf4,0xd8,0x85, -0x42,0x57,0x44,0xb4,0x83,0xa7,0xc7,0x0d,0x5d,0x37,0x70,0xe0,0xdf,0xe5,0xc9,0x1c,0xd2,0xeb,0x48,0xd0, -0x75,0xb1,0x3e,0x13,0xba,0x5b,0x0b,0xdd,0x41,0xe8,0xa5,0x46,0xd9,0x1b,0xf8,0x32,0x69,0x17,0x42,0xf3, -0x02,0xc4,0x48,0xa3,0xc3,0xf0,0x4d,0x85,0x2a,0xea,0x49,0x56,0xd0,0xe4,0xcd,0x2a,0x9a,0xbc,0x0f,0xde, -0xd4,0xd2,0x64,0x18,0xbc,0x5f,0x43,0x93,0xa1,0x8d,0x26,0x38,0x41,0xf5,0x2e,0x62,0x07,0x87,0x36,0x72, -0x20,0xbc,0x09,0xf6,0x5e,0xa3,0xc3,0x50,0x7c,0x55,0xbb,0xfc,0x7b,0xa5,0xcb,0xda,0x1b,0xae,0xe8,0xf4, -0xef,0xab,0x3a,0xfd,0x4b,0xf0,0x7b,0x6d,0xa7,0x3f,0x06,0xbf,0xac,0xe9,0xf4,0x47,0x6b,0xa7,0x79,0x64, -0xb9,0xeb,0xa2,0x37,0x1f,0xad,0x9d,0x66,0xc0,0x4e,0x01,0xf6,0x8b,0xd6,0xe9,0x8f,0xe2,0xab,0xda,0xe9, -0xcf,0x95,0x4e,0x17,0x2f,0xbe,0xa2,0xcf,0x9f,0x57,0xf5,0xf9,0x3a,0xf8,0x5c,0xdb,0xe7,0x77,0xc1,0xf5, -0x9a,0x3e,0xbf,0x5b,0xd1,0x67,0x1e,0x43,0x54,0xb9,0xc7,0xaa,0x56,0xf4,0x99,0x01,0x69,0xc2,0x5f,0x6b, -0x7d,0x7e,0x27,0xbe,0xaa,0x7d,0x7e,0x55,0xe9,0xf3,0x8b,0x52,0x97,0x5f,0xad,0xea,0xf2,0x69,0xf0,0xaa, -0xb6,0xcb,0x9f,0x82,0xd3,0x35,0x5d,0xfe,0x54,0xe9,0xf2,0x37,0x57,0x9d,0x0e,0x16,0x35,0x33,0xfc,0xee, -0x63,0xfe,0xef,0x7b,0x84,0xb8,0xb2,0x41,0x7c,0x27,0xff,0x03,0x88,0x8e,0x15,0xe2,0x90,0x72,0xae,0x2c, -0x39,0x8f,0xb5,0xda,0x3b,0x1d,0x1b,0xc4,0x0f,0x5a,0xed,0x57,0x36,0x88,0xae,0x42,0xfd,0x54,0x23,0xfb, -0x27,0xf1,0x55,0x25,0xfb,0x8b,0x0a,0xd9,0x95,0xba,0x8d,0x20,0xfb,0x8b,0x55,0x64,0xbf,0xb0,0x3b,0x3a, -0x50,0xda,0xb6,0xcd,0x05,0xec,0xfc,0x73,0xb7,0x7f,0xe1,0xa7,0xe5,0x63,0xed,0x02,0x8f,0xc0,0x0b,0x7f, -0x5c,0x4d,0x1f,0x63,0xfa,0xb0,0x9a,0x3e,0xe4,0x33,0xef,0x6d,0xf0,0xa2,0x76,0xa8,0x5f,0x06,0x6f,0xd7, -0x0c,0xf5,0xcb,0x9a,0xd9,0x7d,0x81,0x16,0xcf,0x1e,0xfe,0x1d,0x8b,0xbf,0x43,0x5e,0xb2,0x2f,0x6b,0x66, -0x79,0x09,0xbd,0xb9,0xd5,0xf0,0xba,0x3e,0x15,0xab,0x7e,0xab,0x0d,0xd1,0x4b,0xf1,0x55,0x1d,0xa2,0xd7, -0x95,0x21,0x52,0xaa,0x44,0x62,0x88,0x5e,0xaf,0x1a,0xa2,0xe3,0xf5,0x43,0x74,0x09,0xe7,0x58,0xff,0xb8, -0x3a,0x44,0xc7,0x38,0x44,0xc7,0xd5,0x21,0x3a,0xc6,0x21,0x3a,0xae,0x0e,0xd1,0xb1,0x1c,0xa2,0xe7,0xc1, -0xeb,0xda,0x21,0x3a,0x0b,0x9e,0xaf,0x19,0xa2,0xb3,0x9a,0x21,0x3a,0x16,0x43,0x74,0x2c,0x86,0xe8,0x58, -0x0e,0xd1,0x59,0x75,0x0d,0x74,0x68,0x0d,0x3c,0xd7,0x08,0x7c,0x26,0xbe,0x4c,0x02,0x6f,0x74,0x95,0x35, -0xe4,0xd0,0xa5,0x67,0x88,0xf5,0x37,0xd9,0x3a,0x51,0x0f,0x5d,0x2c,0xc9,0x78,0x80,0xae,0xa9,0xf9,0x16, -0xd7,0xd4,0x1a,0x59,0x05,0xce,0x85,0xb8,0xf6,0xba,0x97,0xd9,0xcb,0x09,0xad,0x01,0x7c,0x36,0xb6,0xe6, -0x0b,0xf5,0x45,0x00,0x10,0xda,0xe0,0x97,0x49,0xd6,0x3c,0xd8,0x93,0x8f,0xba,0x30,0x91,0x5c,0xf8,0x5f, -0x26,0x35,0xc3,0xb3,0x78,0x66,0xcb,0x9d,0x06,0xb1,0x64,0x80,0xf6,0x0f,0xe0,0xe6,0x1b,0x2b,0xe6,0x63, -0xff,0xa0,0x9f,0x31,0xff,0x42,0xac,0x8e,0x37,0x6d,0x25,0x7b,0x1a,0x2c,0x31,0x1d,0xae,0x27,0x40,0x60, -0x78,0x1d,0x6f,0xd4,0x9e,0xed,0xe9,0xe5,0x05,0x48,0xb7,0x24,0x75,0x34,0x7c,0xa1,0x48,0xcf,0x3f,0xf5, -0x10,0xbb,0xbb,0x9d,0xb2,0xd8,0x12,0x6e,0xa7,0x83,0x90,0x1b,0x4e,0xe6,0xe1,0x25,0x5c,0xfa,0xf1,0x48, -0xeb,0x95,0x93,0xba,0xed,0x66,0xea,0x2f,0x9f,0xf8,0x07,0x03,0xff,0xa0,0x07,0xbf,0x84,0xe8,0xa2,0xc2, -0x01,0x57,0x4e,0xb4,0x49,0xed,0x58,0x2d,0x6c,0x65,0xe5,0x48,0xf5,0x17,0x1a,0x31,0x80,0xc2,0x7b,0x13, -0x93,0x93,0x93,0xfe,0x71,0x2d,0x42,0x28,0xa3,0xf9,0xcb,0xda,0xe6,0xe7,0xb6,0xb2,0xaa,0xf9,0xb9,0xd6, -0x7c,0xb3,0xdb,0x86,0xe1,0x05,0x36,0xd1,0x86,0xc2,0x89,0x4d,0xc2,0x65,0xa0,0xb0,0x8a,0x39,0xb1,0x94, -0x55,0x28,0x5c,0x95,0x51,0x58,0xba,0x7b,0x27,0x36,0x14,0xc6,0x36,0xf1,0xd9,0x5a,0x36,0x42,0xf2,0x10, -0x96,0xb2,0x0a,0x85,0x65,0x19,0x85,0xd4,0xdd,0x1b,0xdb,0x50,0xb8,0xb1,0xcb,0xe6,0x0c,0x24,0x6e,0x6a, -0x91,0x78,0x63,0x2f,0xad,0xd0,0x78,0x53,0x46,0x63,0xec,0xee,0xdd,0xd8,0xd0,0x78,0x6f,0x15,0xfd,0x19, -0x58,0xbc,0xaf,0xc5,0x62,0x68,0x2d,0xac,0x90,0x18,0x96,0x91,0x18,0xba,0x7b,0xef,0x6d,0x48,0xfc,0x6e, -0x17,0x2c,0xae,0xbd,0xce,0xcb,0xbb,0xbc,0xb5,0xb4,0x42,0xe3,0x97,0x32,0x1a,0xa1,0xbb,0xf7,0x7b,0x19, -0x8d,0x6d,0x76,0x7c,0xd2,0x71,0x83,0xbd,0x20,0xa8,0x7a,0xb8,0xb3,0xbc,0x5b,0xd6,0xbc,0x5a,0x6e,0xd2, -0xd2,0x29,0x29,0x4a,0x6c,0x7b,0xb2,0x94,0x5f,0x5f,0xca,0xc6,0x2b,0xe2,0x31,0x5c,0x86,0xb7,0x42,0xe7, -0xb8,0x15,0x03,0x97,0x32,0x48,0xe9,0x6d,0x49,0x38,0xa6,0x42,0x95,0x02,0x26,0x6e,0x61,0xcf,0xe0,0x18, -0x2e,0x98,0x9a,0x9a,0xb0,0x84,0xdd,0xd7,0xc8,0xaa,0x28,0xcd,0x5f,0x1e,0xf9,0x87,0x03,0x51,0x87,0x88, -0x7b,0xe4,0x0c,0xa7,0x21,0x3d,0x57,0x97,0x92,0x6f,0xc8,0xf7,0xbf,0xbb,0x42,0xf9,0x84,0x89,0x76,0x4c, -0x11,0x68,0xf1,0x76,0x91,0x26,0x53,0x43,0x9f,0x43,0x8a,0x56,0x8b,0x67,0x54,0xfd,0x6c,0x0d,0xf5,0x72, -0x0e,0xab,0x37,0x75,0x76,0x94,0xe7,0x23,0x79,0x5a,0x36,0x4b,0xcf,0x54,0x1a,0x59,0xe8,0xb0,0x34,0xce, -0x70,0xa9,0xd1,0x01,0x58,0x86,0xe3,0xe8,0x7f,0xf0,0x89,0x44,0x3a,0x81,0x7d,0xb6,0xa4,0xe0,0x19,0x64, -0x7e,0x51,0xf8,0xd8,0x23,0x8a,0x12,0x6c,0x50,0x03,0x8a,0x9e,0x12,0x09,0xc0,0x63,0xc0,0x7f,0xac,0x03, -0xfc,0x07,0x3d,0x20,0xab,0xb5,0x63,0x5e,0x0e,0xa4,0x23,0xfe,0x78,0xe5,0x1d,0x60,0x16,0x34,0xad,0x00, -0xc5,0x25,0x40,0x62,0xdd,0x8e,0xf1,0x09,0x2d,0xc3,0x07,0x6d,0x1f,0x0f,0xee,0xb6,0x76,0x66,0xbb,0xfb, -0x4d,0xfd,0x0b,0x6d,0xc4,0xda,0xa2,0xdc,0x3f,0xf4,0x72,0xb0,0x50,0xdb,0xfa,0x41,0x4e,0xe5,0xb4,0x4f, -0xba,0x1c,0xd5,0x3a,0x07,0x73,0x59,0xc6,0xaf,0x10,0x6a,0xc6,0xda,0x9d,0xf3,0xa9,0x70,0x59,0x76,0x32, -0xc5,0xbb,0x25,0xdd,0xf9,0x04,0x9e,0xd2,0x9f,0x18,0x7d,0xb9,0x2b,0xd0,0x36,0xb0,0x5e,0x5f,0x39,0x76, -0x46,0xd5,0x0d,0x1f,0xee,0xea,0xae,0xb1,0x30,0xdd,0xa2,0x83,0x37,0x33,0x34,0xf0,0xa6,0xa4,0x7f,0x37, -0x3a,0xea,0xc2,0x7c,0x19,0x05,0x5d,0xbc,0x08,0xa1,0x07,0xb5,0xdd,0xdd,0xd1,0x13,0xfe,0xa5,0x7c,0xa9, -0x11,0x80,0x08,0x12,0x30,0x09,0xd8,0xa5,0xb3,0xb0,0xbf,0x2b,0xf4,0xf2,0xa6,0xfb,0x33,0xc0,0x44,0xdd, -0xcf,0xdc,0xfe,0xe4,0x09,0xce,0xc4,0x49,0x2b,0xf0,0x0f,0xa1,0xc3,0xfa,0x87,0x7c,0x9f,0x7e,0x91,0x2d, -0x9b,0x13,0x6f,0x84,0xd1,0x44,0xdc,0xc2,0xf6,0xb2,0x32,0xcf,0x4c,0xf1,0x7e,0xed,0x7c,0x93,0xda,0x95, -0x48,0xdd,0x9a,0x29,0xe1,0xee,0x17,0x94,0xda,0x60,0x06,0x68,0xf5,0xdc,0x63,0x90,0x8c,0xc6,0xf8,0xe6, -0x05,0x54,0x00,0x9a,0x4d,0x8f,0xba,0xa8,0x71,0xd8,0x97,0xf4,0x5e,0x94,0xe9,0x3d,0x58,0x04,0x9d,0x9e, -0xca,0x3d,0xea,0xb6,0xab,0xe3,0xb1,0xd0,0x07,0x6c,0x01,0x1b,0x60,0x15,0x66,0xf1,0xc4,0x3f,0x6c,0xd9, -0x4a,0xe2,0x10,0x24,0xda,0x79,0xb6,0xd0,0xae,0xbc,0xe2,0xc2,0x6b,0x59,0xec,0xf4,0x36,0xb8,0xbb,0x2b, -0xc7,0x0e,0xd9,0xbb,0x6e,0x7b,0x01,0x63,0x37,0x86,0x7f,0x43,0x6b,0x11,0xf1,0x50,0x68,0x16,0x0a,0xfd, -0xd4,0xe3,0x82,0xf6,0x42,0xfc,0x6a,0x58,0x2d,0x83,0x0d,0xa1,0xc2,0xa2,0xad,0xcc,0x0b,0xb3,0x08,0xce, -0x2b,0x6c,0x20,0xa3,0x99,0x65,0x2b,0x40,0x8f,0xa6,0x66,0x81,0xd0,0x9f,0x08,0xbc,0xec,0x45,0xe8,0x05, -0xb5,0x5a,0x04,0x5b,0xa9,0x43,0x4b,0xbc,0x6c,0x16,0x85,0x28,0x81,0xd4,0x2e,0xef,0x56,0x68,0x48,0xc8, -0x58,0x81,0x75,0x57,0x03,0x3a,0x19,0x56,0x16,0x67,0x75,0xc5,0xb2,0x6e,0xb0,0xa9,0x07,0xa0,0x07,0xeb, -0x0c,0x82,0x88,0x9c,0x76,0xa7,0xc2,0x22,0x14,0x95,0x14,0xa4,0x67,0xc6,0xa3,0xa0,0x23,0xcf,0x76,0x3e, -0x6e,0x0d,0x87,0x7b,0x7a,0xfa,0x9e,0xda,0x5a,0xba,0x1d,0xad,0x02,0xa9,0xa6,0x6b,0xc9,0xa8,0x3d,0xe6, -0xa3,0x15,0x27,0x74,0x56,0xed,0x5f,0xf1,0xe6,0xa9,0x7b,0x08,0x83,0x7e,0xcb,0x4e,0xc6,0x03,0x53,0xed, -0x26,0x86,0x12,0xbd,0xd5,0xb7,0xa7,0xac,0x32,0x0a,0xe4,0x00,0x92,0x2b,0xac,0x3c,0x17,0x45,0xaa,0x01, -0xbe,0xec,0x20,0x6c,0x4f,0xfa,0x48,0x48,0x07,0xda,0x64,0x0e,0xd1,0x6b,0xb0,0x07,0xc3,0x04,0xff,0x86, -0xf0,0x2f,0xd4,0x21,0x27,0x03,0x6d,0x7e,0x21,0xe4,0x04,0x20,0x32,0xf8,0xb7,0x2c,0x43,0x86,0x03,0x73, -0x52,0x89,0xec,0xb5,0x7d,0x42,0x0c,0x0c,0xca,0x79,0x64,0x8f,0x0d,0xf4,0x93,0x8a,0xa3,0xf4,0xae,0x1e, -0xec,0x74,0xa4,0x83,0x44,0xed,0x36,0x92,0xf8,0x70,0x2f,0x84,0xbd,0x63,0x1c,0xa4,0xf0,0xff,0x61,0x10, -0x7b,0x8c,0x0e,0x1a,0x1d,0x27,0x30,0x31,0xb2,0xe2,0x75,0x5c,0x9a,0x80,0x73,0x13,0x6a,0x20,0x12,0x0c, -0x29,0x05,0xbd,0x4a,0x30,0x9a,0x14,0xf4,0x2c,0xc1,0x40,0x52,0xd0,0xbb,0xda,0xeb,0x6d,0xe5,0x22,0x1c, -0x8a,0xe5,0xa4,0xdd,0x6e,0xd7,0xde,0x84,0xb9,0xdf,0x25,0x6b,0x74,0xb4,0xeb,0xd6,0x97,0x95,0x1a,0x1e, -0xca,0x24,0x5d,0xdf,0x78,0xf5,0x34,0xc4,0x31,0xfa,0x02,0x5a,0x4e,0x88,0x96,0x19,0xd1,0x72,0xb9,0x8a, -0x96,0x4a,0x9e,0x56,0xa6,0x65,0x0a,0xb4,0x4b,0x69,0x3c,0x66,0x30,0x9f,0x70,0x44,0x66,0x30,0xa7,0xfe, -0x74,0x5a,0x56,0x2d,0xfb,0x2d,0xb4,0xe4,0x09,0xbc,0x31,0x2d,0x69,0x16,0x5b,0xd7,0x5a,0x43,0x51,0x93, -0xf4,0xbc,0x02,0xa5,0xc3,0x29,0xb7,0xa3,0x68,0x8b,0x1e,0xe7,0xf7,0xe9,0xf1,0x24,0xb9,0xb1,0xfb,0xb8, -0xe6,0x0b,0xbc,0xc7,0xaa,0x16,0xe8,0xb3,0xa1,0xa4,0x85,0x62,0x6e,0xb8,0xf8,0xcc,0xcc,0xee,0x71,0xc9, -0x1f,0xa9,0xd4,0x5c,0xcb,0x56,0x2a,0xf1,0x02,0x2d,0x51,0xf0,0xb8,0xd3,0x41,0xb5,0x3a,0x21,0xab,0xba, -0x45,0x3f,0xb5,0xe9,0xc6,0x37,0x11,0xa9,0x9b,0xf1,0xc2,0x78,0x93,0x27,0x97,0xb7,0xf5,0x95,0x54,0x2f, -0xb4,0xe2,0x8d,0x7e,0x63,0x5d,0xdb,0x15,0x3c,0xab,0xa6,0x53,0x9f,0x32,0xaf,0x88,0x76,0x03,0xe1,0x08, -0x06,0x04,0x55,0x7a,0x34,0xdf,0xc1,0xa8,0xca,0xa3,0xbb,0xff,0x45,0xb5,0x30,0x1f,0x55,0xf3,0x48,0x93, -0xd5,0x6a,0x95,0xef,0x2a,0x4d,0xbf,0xac,0x72,0x24,0x2b,0xdd,0x31,0x79,0x87,0x2c,0x6c,0xc8,0xb3,0x4b, -0x60,0xd9,0xa6,0x67,0x40,0x6b,0xe4,0x55,0x36,0xa7,0x6e,0x7f,0xf6,0x24,0x19,0x14,0xd5,0x20,0xf2,0xd0, -0xdf,0xe6,0xad,0xaa,0xaf,0x37,0xbb,0x83,0x6d,0xbb,0x3c,0x08,0x47,0x49,0x4b,0xd7,0x8f,0xe3,0x64,0xb8, -0xc4,0x19,0x40,0xbb,0xbb,0xab,0x2b,0x2e,0x57,0xda,0xae,0x56,0xd9,0x2a,0x55,0x79,0xb7,0x4a,0x37,0x13, -0x29,0x6d,0xb3,0x5a,0x37,0xb4,0x25,0xf0,0x23,0xa8,0x55,0x7d,0x20,0xe6,0x13,0x87,0xf2,0x35,0xac,0x2c, -0x83,0xdf,0x37,0x87,0xb5,0x76,0xf0,0x58,0x29,0x8f,0x36,0x0b,0xa1,0x65,0x1b,0xdc,0xde,0xad,0xd2,0x0e, -0x36,0x14,0x40,0x74,0x8c,0x6b,0xfd,0xb6,0x4b,0x5d,0x50,0xe1,0x45,0x43,0x42,0x97,0xf4,0x58,0x29,0x8e, -0x89,0x3d,0x8b,0xd7,0x62,0x94,0x63,0x04,0x0d,0xa0,0xae,0xee,0x38,0x1e,0x76,0x02,0xc1,0xd6,0xd7,0x28, -0xcc,0xde,0xb9,0x62,0xa3,0x9f,0x85,0xcb,0x78,0x1c,0xe6,0xb0,0x85,0xa1,0x96,0xed,0xf1,0x18,0xd9,0x6e, -0xe1,0x4d,0xe9,0x78,0x36,0x4a,0x71,0xd3,0xf3,0xf7,0x1a,0x3f,0xc5,0xb0,0xd4,0x92,0x4f,0xfb,0x80,0xcd, -0xda,0x06,0x6d,0x58,0x6a,0xd9,0x18,0x77,0x97,0xd4,0x5a,0x0d,0x53,0xc8,0x0d,0x10,0xbe,0x33,0x86,0xa3, -0xa2,0x65,0x7d,0x9f,0x01,0x50,0xa6,0x2f,0xda,0xda,0xfe,0xe3,0x8f,0xa6,0x32,0x13,0x48,0x8b,0x2d,0x42, -0x88,0x9a,0x68,0x9b,0xc0,0x05,0xc1,0x35,0xc3,0xfd,0x6b,0x3c,0xc6,0x68,0x92,0x22,0xb0,0x81,0x0d,0x45, -0xd2,0xd1,0xb5,0x4a,0x6f,0x56,0x61,0x87,0xda,0x39,0xfa,0x2d,0xb2,0x68,0xdd,0xed,0xc3,0xe1,0x1c,0x17, -0xb7,0xc8,0xcc,0xdb,0xe9,0x5a,0x9a,0x65,0x8c,0xbe,0x6a,0xbb,0x71,0xb1,0x8a,0x94,0x53,0x76,0x98,0x10, -0x03,0x13,0x99,0x0e,0x5a,0x47,0x48,0x40,0xe9,0xd7,0x7d,0x77,0x77,0x07,0xb0,0x76,0x1c,0x93,0x8c,0x5a, -0xed,0x6c,0xe7,0x27,0x65,0x74,0x7a,0x77,0xaa,0xc6,0x0e,0x5b,0x0f,0x35,0x9f,0x8d,0x52,0x8a,0x98,0x1a, -0x1b,0xbf,0x26,0x2a,0x04,0xee,0x49,0x0c,0xa8,0x68,0x5b,0xe8,0x67,0x3b,0x36,0x7c,0x4a,0xa6,0x07,0x5f, -0x88,0x13,0x89,0x1c,0x56,0x6b,0x84,0xc7,0xab,0x35,0xc2,0xa5,0x49,0x8b,0xb4,0xc6,0x89,0x50,0x82,0x06, -0xa8,0xbb,0xd2,0xe8,0xc9,0x4c,0xa6,0xe3,0xab,0x1a,0xa7,0x42,0x38,0x33,0xbf,0xc5,0xdc,0xde,0x87,0xf3, -0xbb,0x42,0xf4,0x07,0x77,0xc2,0x92,0xb1,0xa5,0x94,0xf5,0x91,0xcd,0x65,0x48,0x15,0xfa,0xf3,0x45,0x36, -0x69,0x66,0x1f,0x12,0x8c,0xc3,0x69,0x74,0x3c,0x5b,0x64,0xa8,0x22,0x1b,0x8d,0x9e,0x31,0x02,0x18,0x75, -0x75,0x95,0x59,0xca,0xd7,0x1b,0xe3,0x1d,0x73,0x90,0x71,0xed,0x54,0x96,0xad,0x65,0xe4,0x69,0x8b,0x32, -0x71,0xb4,0x19,0x1b,0xd7,0xe3,0x09,0x08,0xa5,0x1c,0x1a,0x2a,0xcb,0x35,0x69,0xa3,0xd4,0x6d,0x2f,0x86, -0xa4,0xd2,0x13,0xb8,0x4c,0x36,0x95,0xcc,0x7b,0x13,0x11,0x2f,0x09,0x50,0x31,0x16,0x74,0xd3,0x15,0x02, -0x22,0xbc,0xb1,0xa8,0x5e,0xb2,0xe8,0x0a,0xb1,0xb5,0x74,0xe8,0x3f,0xaf,0x2b,0x5b,0xf4,0xa0,0x6c,0x5d, -0xfd,0x9f,0xd2,0x85,0xfb,0x8c,0x86,0xdd,0x08,0xfb,0xbf,0xb9,0x47,0xba,0xb3,0xa5,0xaf,0xff,0x7c,0x11, -0xaf,0xe8,0x3c,0x30,0xae,0x75,0x9d,0xc7,0xdb,0x76,0xa8,0x6d,0xbb,0x1a,0x33,0x64,0x9a,0xf3,0xb8,0xb7, -0x61,0xcd,0x05,0x21,0x29,0xba,0xce,0xbb,0x35,0x35,0x72,0xf1,0xe3,0xeb,0x57,0x67,0x17,0x67,0x70,0x25, -0x7f,0xfe,0xec,0xed,0xc5,0xb3,0x5f,0x9f,0xbd,0x3a,0x7b,0x87,0xed,0xdd,0xdf,0xde,0x2c,0xb9,0xa7,0xbd, -0x99,0x60,0xd9,0x93,0x95,0x1b,0xb0,0xab,0x6f,0xed,0x33,0xb5,0xb5,0x4f,0x91,0x79,0x87,0xaa,0x50,0xeb, -0xb7,0x3f,0x7a,0x32,0x95,0x7b,0xfc,0x08,0xf6,0xf8,0x02,0x1f,0xa7,0xd5,0xc4,0x50,0x95,0xd3,0x0f,0xa3, -0x73,0x1f,0xa3,0xc9,0x64,0xf3,0xf0,0x32,0x1a,0x38,0x4e,0xcf,0xf1,0x9d,0x96,0x99,0xea,0x7a,0xf4,0x3d, -0x61,0x64,0xdd,0x3b,0x6d,0x24,0xe1,0x02,0x50,0x18,0x62,0x8a,0x67,0xa5,0xd0,0xf6,0xf6,0x85,0x7c,0xed, -0x46,0xf3,0x94,0xad,0x97,0x92,0xf2,0xd4,0xc4,0xb8,0x65,0xcc,0x71,0xd8,0x3d,0x70,0x59,0x17,0xd9,0x56, -0x93,0x33,0x55,0x93,0x33,0xa7,0x27,0x45,0x20,0xf1,0x8f,0x6c,0x34,0xdd,0x94,0x3e,0xd8,0xbe,0xc6,0x62, -0x95,0x5e,0x08,0xad,0x44,0xca,0x2d,0x8b,0x12,0x7b,0xe7,0x50,0x20,0x32,0xf3,0xb4,0xd5,0xdc,0x87,0x59, -0x3b,0x4f,0x5d,0x6f,0x98,0x78,0xfa,0x86,0xbd,0x15,0x1c,0xb1,0xb6,0x70,0x55,0xf9,0xba,0x5b,0x77,0x5e, -0xe5,0xda,0xcb,0x2c,0xfb,0x9d,0xb1,0x8b,0x18,0x3e,0xf0,0xca,0x56,0xed,0xcc,0xc4,0x58,0x8d,0x4d,0x8b, -0xeb,0xae,0xd5,0x14,0xb5,0x9e,0xe4,0x45,0xdc,0x06,0x65,0x6b,0xa5,0x0d,0x41,0xa6,0xdf,0x2c,0x32,0xf3, -0x66,0x11,0x5a,0x6e,0x16,0x99,0x60,0x26,0x50,0xd6,0x1e,0x69,0xe1,0xd0,0x90,0xb5,0xf9,0x6c,0xb2,0x50, -0x0e,0x47,0x96,0xa5,0xb5,0x4e,0x62,0xa5,0x39,0xa1,0x6c,0x8d,0x5f,0x7f,0x6b,0x86,0x1f,0x42,0xf6,0x48, -0xe7,0xa7,0xe4,0xba,0x8a,0x7c,0x8e,0x67,0x97,0x02,0xcf,0x22,0x7f,0xfa,0xd7,0xc9,0xbf,0xe3,0xe9,0x94, -0xa2,0xa3,0x5a,0x35,0xe7,0xa4,0xb9,0xbf,0xb4,0x04,0x08,0xfc,0x03,0x77,0x2d,0xee,0xa6,0x39,0x2f,0xfb, -0x42,0xc4,0xa8,0xb9,0x3c,0x69,0xde,0xc0,0xea,0xe6,0x80,0xa3,0xca,0x17,0xe2,0x3c,0xc9,0x62,0x0a,0xcc, -0xd4,0x08,0x87,0x59,0x32,0x5d,0xe4,0x51,0xbf,0x81,0x22,0x25,0xb8,0x84,0x36,0x48,0x2c,0x84,0x3f,0x84, -0x29,0x07,0xfe,0x64,0xf3,0x0d,0xf8,0xa5,0xb9,0x4d,0xe4,0xe9,0xaa,0x5c,0x8c,0xc0,0xc0,0x0a,0xff,0x22, -0x4f,0x3f,0x9f,0x8e,0x9a,0xd5,0xb6,0x6b,0x1f,0xce,0xfa,0x2a,0x0a,0x53,0x5a,0xf2,0xc6,0xc7,0x82,0x0e, -0xb1,0xc5,0x63,0x1c,0x4a,0x5c,0x72,0x45,0x95,0x4f,0x17,0xe3,0x9f,0xe2,0x4f,0x06,0x2f,0xcb,0x31,0xfc, -0xbe,0x2a,0x52,0x11,0x07,0x2e,0x45,0xb2,0xd0,0xa3,0x67,0x84,0x32,0x1f,0xe0,0x54,0x57,0x45,0x96,0xea, -0x10,0xcf,0x7c,0x07,0x33,0xaf,0xc9,0x21,0xbd,0xb4,0xa8,0x7a,0xfb,0x38,0x7b,0x8e,0xfe,0x17,0x83,0xa8, -0x0e,0x2b,0x05,0x51,0x03,0x00 +0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xec,0xbd,0xeb,0x7a,0xda,0xca,0xb2,0x28,0xfa,0x2a, +0x0a,0x99,0x33,0x13,0x96,0xb9,0x63,0x6c,0x8c,0x07,0xc9,0x02,0x8c,0x6f,0xf1,0x1d,0x5f,0xe2,0x64,0xe7, +0x8c,0x4f,0x20,0x01,0x8a,0x85,0x44,0x24,0x01,0xc6,0x8e,0xf7,0xfb,0x9c,0x27,0x38,0xff,0xcf,0x79,0xb1, +0x53,0x55,0xdd,0x2d,0xb5,0x84,0xc0,0xd8,0xf1,0x18,0x73,0xad,0xfd,0xad,0x91,0x39,0x13,0x21,0xf5,0xa5, +0xba,0xba,0xba,0x6e,0x5d,0x5d,0xfd,0xc7,0xbb,0x9d,0xd3,0xe6,0xe5,0xed,0x59,0x4b,0x19,0x78,0x43,0xf3, +0xe3,0x1f,0xfc,0x6f,0x5d,0xd5,0x3e,0xfe,0xe1,0x19,0x9e,0xa9,0x7f,0x6c,0xb5,0xcf,0xc6,0x8e,0xa5,0x2a, +0xf9,0x2c,0xfc,0xf9,0x23,0xc7,0x5e,0xfe,0x31,0xd4,0x3d,0x55,0xe9,0x0e,0x54,0xc7,0xd5,0xbd,0x5a,0x62, +0xec,0xf5,0x32,0x95,0xc4,0xc7,0x3f,0x4c,0xc3,0xba,0x53,0x1c,0xdd,0xac,0x25,0xdc,0x81,0xed,0x78,0xdd, +0xb1,0xa7,0x18,0x5d,0xdb,0x4a,0x28,0x03,0x47,0xef,0xd5,0x12,0x9a,0xea,0xa9,0x55,0x63,0xa8,0xf6,0xf5, +0xdc,0xc8,0xea,0x6f,0x77,0x54,0x57,0xdf,0x58,0x4f,0xd7,0xeb,0xf5,0x46,0xbd,0xde,0xaa,0xb7,0xe0,0x6f, +0xfc,0xf7,0xa0,0xde,0xb0,0xf1,0x71,0xb7,0x0f,0x7f,0x35,0xf1,0xaf,0xfa,0x39,0xfe,0x75,0x50,0x17,0xdf, +0xc5,0x7f,0xf0,0xba,0x71,0x7c,0x04,0x0f,0x97,0xcd,0x69,0xfd,0xc5,0xff,0x1d,0x9e,0xe5,0xf2,0xf5,0xfe, +0xcb,0xeb,0x2d,0xfd,0xaf,0x79,0x99,0xdb,0xda,0xaf,0xdc,0xe5,0x72,0xe7,0xbd,0xd7,0xc0,0xb3,0x33,0xdf, +0xe0,0x46,0xee,0xe1,0xf6,0x47,0x6e,0x72,0x99,0xc3,0xef,0x9d,0xe8,0x38,0xb1,0xbf,0xdd,0xdb,0xe5,0xf0, +0x1c,0xb6,0x00,0x9e,0xf6,0x0d,0xd6,0x3f,0x64,0x6f,0x5b,0xf9,0xde,0xc6,0x70,0x6f,0xb2,0x5f,0xca,0xcd, +0xbe,0xe4,0xb6,0x8e,0x5d,0xf6,0xf6,0xe4,0x28,0xd7,0xbd,0x9f,0xcc,0xb6,0x72,0x04,0xff,0x70,0x19,0xac, +0x77,0xbd,0x4a,0x6b,0x7f,0xf2,0xa5,0xb8,0xd6,0x86,0xfa,0x67,0x95,0x1f,0x95,0xde,0x97,0x93,0xc6,0xf1, +0x64,0x6d,0xad,0x9e,0x33,0xd7,0x72,0x95,0xeb,0x8d,0x9c,0x95,0xab,0xbb,0x97,0x6b,0xa5,0xba,0x3a,0xce, +0x4d,0x2a,0xc3,0x5c,0xee,0xf2,0xf3,0x6a,0x58,0xd8,0x39,0xcc,0x95,0x8e,0x4f,0x4a,0xb9,0x49,0xae,0xb5, +0x36,0x29,0xe7,0xa6,0x0d,0x33,0x97,0xab,0xd4,0x7b,0xb9,0x5c,0x6e,0xef,0xb0,0x97,0xcf,0x4d,0x77,0x3b, +0xf0,0xfb,0x2a,0x3f,0xb1,0x08,0x1f,0x37,0xe7,0xf1,0xe0,0x01,0xfc,0x07,0xf8,0xfd,0xa4,0x0d,0xe3,0xdf, +0xeb,0x43,0xff,0xa7,0x7b,0xcd,0xad,0x87,0x4a,0xee,0xfc,0xcb,0xd7,0xdc,0x64,0xeb,0x5c,0x3f,0xb1,0x72, +0xdd,0x87,0x1f,0x7b,0xb9,0xc2,0xa8,0x91,0x87,0xf6,0xbf,0x4e,0x72,0xb9,0x9d,0xc3,0x1f,0x95,0xdc,0xfd, +0x66,0x67,0x6b,0x52,0x81,0x3e,0x2f,0x2f,0x0f,0xcf,0x36,0xf3,0xaa,0xd4,0x3e,0xb6,0x77,0x61,0x40,0x7b, +0x9f,0x6f,0xa1,0xfd,0xcb,0xf5,0xc3,0x5e,0x2e,0x9f,0xbb,0xdf,0x31,0xd6,0x26,0x95,0x5d,0x37,0xb7,0x09, +0x18,0x9b,0xf4,0x72,0x9b,0xfd,0xce,0xe8,0x6c,0xed,0x7e,0x7f,0xa3,0x97,0x3b,0xd9,0xdd,0x1f,0x02,0xfc, +0x43,0x84,0xff,0xcb,0x59,0x2e,0xd7,0xfa,0x39,0xd9,0x20,0x7c,0x9f,0x21,0x7e,0x2f,0x1f,0xb0,0xbd,0xab, +0xe8,0x7c,0x36,0xbe,0x7c,0xdd,0xfa,0x7a,0xbe,0xeb,0x9d,0x95,0x72,0xf5,0x0d,0x00,0xea,0x61,0x76,0xba, +0x3e,0xa9,0x9c,0x7c,0x81,0xf1,0x76,0x1e,0xac,0x03,0xde,0xde,0xc1,0x8f,0x5c,0x29,0xd7,0x1a,0x1f,0x6d, +0x14,0xee,0xf7,0xad,0x35,0xab,0x3f,0xca,0xe5,0x8e,0xb5,0x78,0x7c,0xce,0x36,0xb6,0x1a,0xee,0xd1,0x78, +0xf2,0x25,0xd7,0xd2,0xbf,0x6c,0xe4,0xa6,0x9b,0x7d,0x98,0x9f,0xfd,0x87,0x1e,0xb4,0xbf,0xbb,0x99,0xcb, +0x4d,0x7f,0x9e,0xc0,0xef,0x46,0x17,0xba,0x6a,0xda,0x3b,0x95,0xdc,0xec,0x47,0xae,0x52,0x3c,0x7e,0x76, +0x96,0xee,0x72,0x07,0x6d,0x1c,0xbf,0x3b,0xeb,0xe0,0x78,0x2e,0xca,0x67,0x4e,0xae,0xe1,0x58,0x5b,0xb9, +0x69,0xdb,0x80,0xf9,0xfe,0x5c,0x9a,0x3c,0xe4,0x1a,0x5b,0x0e,0xfc,0xce,0xb5,0x01,0x3f,0x3f,0xd6,0xce, +0x2e,0x37,0x0f,0x72,0xb9,0x7c,0x23,0x7e,0xbe,0x7c,0xfc,0x9e,0x22,0xbd,0x9e,0x11,0xfe,0x73,0x3b,0x5a, +0x6e,0x73,0xe3,0xfc,0xf2,0x24,0x37,0xae,0x7c,0xad,0xe4,0x7e,0xe4,0x0e,0x27,0xb9,0x87,0xf5,0xfa,0xce, +0x11,0xf4,0x8a,0xf4,0x31,0x20,0xfc,0xcf,0xa0,0xfc,0xc1,0x92,0xc5,0x8f,0xed,0x1d,0x4d,0x01,0xdf,0x17, +0x65,0xf6,0x62,0xe7,0x38,0xb7,0x71,0x77,0x50,0x38,0x9b,0xae,0x61,0x7f,0xac,0xbe,0x1b,0x2e,0xdf,0x44, +0xfa,0xb9,0xbc,0xc5,0xef,0xfb,0x71,0xeb,0x4d,0xe2,0x40,0xe2,0xbf,0x87,0x5e,0xe5,0xc6,0xff,0x7e,0x8a, +0xf4,0x71,0x5e,0x5a,0x08,0x4f,0xe3,0x79,0xfc,0x46,0xfe,0xc3,0xf5,0x3b,0xcf,0x1a,0x7e,0xf3,0xbf,0x97, +0xf2,0x3f,0x98,0xd7,0x7a,0xfd,0xac,0x9c,0x03,0x1c,0x76,0x35,0xc0,0xcb,0x7d,0xab,0x5b,0xaf,0x1f,0xd7, +0xcf,0xe0,0x77,0x7f,0x87,0xf0,0x24,0xc6,0xb5,0xd3,0xaf,0xc3,0xef,0x69,0xbd,0x82,0xaf,0xf6,0xe1,0x77, +0xbd,0x01,0xbf,0x67,0x7b,0xf0,0xfd,0x68,0xb4,0x09,0xbf,0xd7,0x72,0x53,0xde,0x5e,0xbd,0x56,0x4b,0x70, +0x69,0x62,0xa9,0x43,0xbd,0x96,0x98,0x18,0xfa,0x74,0x04,0xb2,0x23,0xa1,0x80,0xe0,0xf0,0x74,0x0b,0xa4, +0xcb,0xd4,0xd0,0xbc,0x41,0x4d,0xd3,0x27,0x46,0x57,0xcf,0xd0,0x8f,0xb4,0x61,0x19,0x9e,0xa1,0x9a,0x19, +0xb7,0xab,0x9a,0x7a,0xad,0x00,0x4d,0xb8,0xde,0x0c,0xe4,0x12,0x8a,0xaf,0xc7,0xcc,0xd0,0xcd,0x78,0xfa, +0xbd,0x97,0x71,0x8d,0x07,0x3d,0xa3,0x6a,0x3f,0xc6,0xae,0x57,0x2d,0xe4,0xf3,0xff,0xdc,0xce,0x4c,0xf5, +0xce,0x9d,0xe1,0x2d,0xf8,0xda,0x83,0x0e,0x33,0x3d,0x75,0x68,0x98,0xb3,0xaa,0xab,0x5a,0x6e,0xc6,0xd5, +0x1d,0xa3,0xf7,0xd4,0xb1,0xb5,0xd9,0xe3,0x50,0x75,0xfa,0x86,0x55,0xcd,0x3f,0xa9,0x8e,0x67,0x74,0x4d, +0x3d,0xad,0xba,0x86,0xa6,0xa7,0x35,0x00,0xdc,0x30,0xdd,0x74,0xcf,0xe8,0x77,0xd5,0x91,0x67,0xd8,0x16, +0x3e,0x8e,0x1d,0x3d,0xdd,0xb3,0x6d,0x4f,0x77,0xd2,0x28,0x49,0xf1,0x9f,0xbe,0x63,0x8f,0x47,0xe9,0xa1, +0x6a,0x58,0xe9,0xa1,0x6e,0x8d,0xd3,0x96,0x3a,0x49,0xbb,0x7a,0x97,0x6a,0xb8,0xe3,0x21,0x34,0x3f,0x7b, +0xd4,0x0c,0x77,0x64,0xaa,0xb3,0x6a,0xc7,0xb4,0xbb,0x77,0x4f,0xea,0x58,0x33,0xec,0x74,0x57,0xb5,0x26, +0xaa,0x9b,0x1e,0x39,0x76,0xdf,0xd1,0x5d,0x37,0x3d,0x81,0x5e,0x6d,0xbf,0xa4,0x61,0x81,0xc4,0xd5,0x33, +0x54,0x61,0x7b,0xa2,0x23,0x68,0x80,0x14,0xd5,0x34,0xfa,0x56,0x15,0xa5,0x2b,0x7e,0x65,0x0d,0x55,0x2d, +0xdb,0x4b,0x7e,0x43,0x94,0x3a,0xb6,0xe9,0x7e,0x4f,0xf9,0x4d,0x58,0xb6,0xa5,0x6f,0x0f,0x74,0xa3,0x3f, +0xf0,0x60,0x74,0xdf,0x06,0x86,0xa6,0xe9,0xd6,0xf7,0xb4,0xa7,0x0f,0xe1,0xb3,0xa7,0x87,0xca,0x3d,0xa9, +0x8f,0x1d,0xb5,0x7b,0x87,0x63,0xb1,0xb4,0x4c,0xd7,0x36,0x6d,0xa7,0xea,0x39,0x80,0xa9,0x91,0xea,0xc0, +0x4c,0x3d,0xa9,0x55,0x15,0x46,0x34,0x01,0xe4,0x54,0x07,0x36,0x80,0xf3,0x68,0x8f,0x3d,0x04,0x01,0xd1, +0xd6,0xe9,0x38,0xdf,0x48,0x77,0xf8,0xfe,0xd8,0xb1,0x1d,0xc0,0x49,0xa6,0x63,0x7b,0x9e,0x3d,0xac,0x16, +0x46,0xf7,0x8a,0x06,0x8f,0xba,0xf6,0xd4,0x49,0xbb,0x00,0x9e,0xd5,0x7f,0xa4,0x99,0x98,0x32,0xa0,0x36, +0xf3,0xf9,0x27,0xad,0x67,0xb1,0x77,0x34,0xcb,0x55,0xc3,0x83,0x21,0x76,0x9f,0x06,0x05,0xfe,0x12,0x26, +0xb2,0x5a,0xd4,0x87,0xdb,0x7c,0x92,0xb2,0x1b,0x9b,0xfa,0x50,0xc9,0x3f,0xc1,0xcf,0x3b,0x09,0xe0,0xea, +0xfb,0x5e,0x2f,0xbf,0xcd,0xa0,0x7e,0x9f,0x87,0x56,0xdd,0xa1,0x6a,0x9a,0x52,0x13,0x95,0xfc,0x3f,0x9f, +0xdc,0x31,0x00,0x31,0x1e,0x49,0x6f,0x37,0xcb,0xff,0xdc,0x26,0x2c,0x0b,0x24,0x6d,0x8f,0x6c,0xd7,0xc0, +0x89,0xab,0x82,0xa6,0xa3,0xe2,0x78,0x17,0xa2,0x1e,0x5b,0xf2,0xec,0x51,0x35,0x93,0x2d,0xeb,0x43,0x6c, +0xfb,0x91,0x0f,0x3a,0x93,0x2d,0xe2,0x1b,0x63,0xd8,0xe7,0xd8,0x00,0x14,0xb9,0x93,0x3e,0xcd,0x52,0xd5, +0x01,0xd2,0x49,0x3d,0x22,0x02,0x7b,0xa6,0x3d,0xad,0xb2,0x29,0x79,0x62,0x74,0x25,0x08,0xb1,0x00,0x23, +0x5c,0xcf,0x8f,0xee,0x9f,0x06,0xce,0xa3,0xa0,0xea,0x8e,0x7d,0x8f,0x20,0x1b,0x56,0xbf,0xca,0xd7,0x0e, +0xbe,0xda,0x5e,0xf0,0xda,0x9f,0xf3,0x11,0xb4,0xea,0x77,0xa6,0x8e,0x3d,0xfb,0xa9,0x6b,0x03,0x69,0xdf, +0x75,0x34,0x20,0x3b,0x3d,0xed,0xaa,0x43,0x8e,0x0e,0xbe,0x34,0x86,0xb6,0x65,0xc3,0x8c,0x77,0xf5,0xb4, +0xff,0xb4,0x1d,0xa0,0x0b,0x00,0x7b,0xea,0x8c,0x61,0x90,0x16,0x2c,0xd2,0xd1,0xd8,0x4b,0xdb,0x23,0x8f, +0x11,0x3f,0xe0,0x04,0x08,0x3e,0x8d,0x6b,0x0f,0xc8,0x45,0x7d,0x64,0x33,0x61,0x58,0x03,0x58,0x65,0x1e, +0xb5,0xe0,0xff,0xf0,0x57,0x1b,0x6b,0x29,0x00,0x6f,0x62,0xb8,0x46,0xc7,0xd4,0x45,0x0f,0xac,0xc9,0x47, +0x5a,0xce,0x44,0x88,0x3d,0xdb,0x19,0x32,0x52,0xe5,0x25,0x90,0x21,0x28,0x04,0xc8,0x37,0x6f,0x36,0xd2, +0x6b,0xec,0xf5,0xf7,0xb4,0xf4,0x0a,0xd6,0x95,0xee,0x85,0xde,0xc0,0x44,0x0d,0x0d,0xef,0xbb,0x8f,0x58, +0x75,0x34,0xd2,0x55,0x68,0xbe,0xab,0x57,0x59,0xfd,0xed,0xee,0xd8,0x71,0x01,0xf8,0x91,0x6d,0x00,0x42, +0x1d,0xde,0xd9,0x37,0x58,0x2b,0x2a,0x40,0xa7,0x7d,0x97,0xbb,0xf5,0x5f,0x3e,0xf2,0x4a,0x9a,0xde,0x53, +0xc7,0xa6,0xc7,0x2b,0x55,0xab,0x99,0xa1,0xfd,0x90,0xe9,0xd9,0xdd,0xb1,0x9b,0x31,0x2c,0x0b,0x98,0x05, +0xd5,0x9b,0x7f,0xef,0x53,0xca,0xf6,0x48,0xd5,0x34,0x9c,0xce,0xfc,0x13,0x15,0x7d,0x94,0xc9,0xd3,0x02, +0x0c,0xa8,0xe6,0x93,0x34,0x9a,0xee,0x40,0xef,0xde,0xc1,0x8c,0x87,0x07,0xad,0x02,0x53,0xf8,0x1e,0x47, +0x3a,0xfe,0xea,0x0c,0x51,0x8e,0xf4,0x36,0xd2,0x3b,0x6b,0xcf,0x1a,0x0f,0x3b,0xba,0xf3,0x1d,0xa0,0xe6, +0x2d,0x12,0xc8,0x19,0x77,0x64,0x58,0x19,0x99,0x1c,0x16,0x94,0x06,0x46,0x11,0x2e,0xfd,0xc8,0x87,0x43, +0xf4,0x28,0x4f,0x0d,0x4c,0x44,0x77,0x10,0x3b,0x35,0x48,0x05,0x3d,0x43,0x37,0xb5,0xed,0x57,0x2d,0x88, +0x98,0x5e,0x02,0xf8,0xd8,0x8b,0x4c,0x17,0x3b,0x32,0x63,0x06,0xb4,0xa8,0x82,0xa6,0x77,0x6d,0x47,0x45, +0x66,0x11,0x07,0x31,0x11,0x2a,0x81,0x0c,0x14,0x28,0xa6,0x17,0xf9,0xa1,0x6b,0x9b,0x86,0xa6,0xb8,0x86, +0x09,0x74,0xef,0x2f,0x06,0xa5,0x38,0x0a,0x90,0x9f,0x2d,0x01,0xff,0x50,0xb2,0x1b,0x45,0xfa,0x67,0x13, +0x99,0x89,0xa9,0xf7,0x75,0x4b,0x8b,0xa3,0x12,0x7f,0xc9,0x85,0x97,0xb9,0x58,0x99,0x73,0xec,0xd6,0x43, +0x82,0x15,0x6c,0x1a,0x96,0xa9,0xa9,0x8e,0x5c,0xbd,0x2a,0x1e,0xb6,0xf9,0x07,0x5c,0xf9,0xbc,0x7d,0x2d, +0xed,0x0d,0x1e,0x83,0xfe,0xb2,0x8c,0x65,0xa5,0x85,0x34,0x09,0x09,0x91,0x77,0xc6,0x10,0xe5,0xbb,0x0a, +0xf2,0x22,0x3b,0xca,0x20,0x07,0x0c,0xc9,0xbd,0x6d,0x69,0xe2,0x61,0xe8,0xf7,0x4c,0xe0,0x93,0x80,0xc6, +0xf2,0x7d,0x92,0xee,0x3d,0x53,0xbf,0xcf,0xd0,0x40,0x1c,0x7b,0xaa,0x4c,0x1d,0x75,0xb4,0xed,0xbf,0xa6, +0xc5,0x00,0xa0,0xdd,0x55,0x5d,0x18,0xb4,0xe7,0x13,0x03,0xb1,0xe6,0x0c,0x9f,0xf0,0x2a,0x15,0x0d,0x17, +0x40,0xb2,0xd0,0x0c,0x87,0x09,0x65,0xbe,0x8e,0x42,0x1f,0x6d,0xc7,0xc0,0xaa,0x60,0xd9,0x1a,0x0f,0xd0, +0x8c,0xf4,0x35,0x06,0x9e,0x85,0xdd,0x89,0xd1,0xe2,0xab,0xed,0x98,0x8a,0x32,0xab,0xdd,0x75,0x74,0xbd, +0x0d,0x6c,0x2d,0x5d,0x77,0x8c,0xa1,0x9d,0xde,0x71,0x6c,0x20,0x0b,0x7a,0xb1,0xaf,0x03,0x6d,0xa0,0xcc, +0xc1,0x4f,0xaa,0x99,0x0e,0xf4,0x95,0x6d,0x53,0xf7,0x3c,0x69,0x7a,0x32,0xd9,0x12,0xf0,0xe4,0x6d,0xe2, +0x91,0x20,0xa5,0x61,0xe6,0xf0,0x2d,0xcc,0xbd,0x31,0x04,0x7e,0xed,0x8e,0x74,0x10,0xbc,0xff,0x39,0xd4, +0x35,0x43,0x55,0x40,0x1c,0x2a,0xaa,0xa5,0x29,0x49,0x44,0xe6,0x00,0xa6,0x81,0xe0,0x77,0x54,0xd7,0xa3, +0x99,0x4b,0xa5,0x63,0x3e,0x30,0x89,0x9f,0x7a,0x24,0x9a,0x51,0x68,0x86,0xc2,0x7a,0xcc,0x53,0xd6,0x1e, +0xe9,0x8e,0x9a,0xb1,0x2d,0x73,0xa6,0x54,0x33,0x76,0x06,0x84,0x0a,0x71,0xb5,0x34,0x15,0x9e,0x02,0x31, +0x49,0xb0,0xae,0x97,0x80,0x92,0xe1,0xc3,0x38,0x5e,0xc7,0x89,0x8c,0x8d,0x4f,0x52,0x64,0x6c,0x44,0x3a, +0x11,0x91,0x0c,0x52,0x78,0x3b,0xd4,0x15,0xaf,0xfa,0x60,0xa3,0x0a,0x42,0x94,0xa5,0x7c,0xeb,0x9a,0xaa, +0xeb,0xfe,0x47,0x0d,0x7a,0xff,0xfe,0xb8,0x40,0x19,0x44,0xd0,0x32,0x85,0x34,0xfb,0x47,0x7a,0x28,0x8a, +0xa7,0xe0,0x61,0x5d,0x3c,0x95,0xc4,0x83,0xff,0xa6,0x2c,0x1e,0x36,0xc4,0x43,0x85,0x3f,0xe4,0x83,0x7a, +0x52,0xab,0x52,0x6b,0xc5,0xe0,0xb1,0x14,0x3c,0xae,0x07,0x8f,0xe5,0xe0,0x71,0x23,0x78,0xdc,0x0c,0x1e, +0x2b,0xc1,0xe3,0x96,0xff,0x58,0x94,0x9e,0x4a,0xe2,0x81,0x83,0x59,0x0c,0x80,0x2a,0x06,0x90,0x14,0xa5, +0x2a,0x01,0x24,0xc5,0x00,0x92,0x92,0xf4,0xe4,0x3f,0x94,0xc5,0x03,0x1f,0x70,0x50,0x7c,0x5d,0x7c,0x2b, +0xfb,0xe3,0x0e,0x86,0x52,0x0e,0x3e,0x6e,0x88,0x07,0xde,0x42,0x30,0xc8,0x4d,0xbf,0xe2,0xa6,0xf4,0x8e, +0x17,0x0b,0x46,0x8d,0x83,0xfe,0xdb,0xa9,0x8b,0x51,0xc4,0x23,0x63,0x66,0xeb,0xd9,0xc2,0xc6,0xc6,0xe6, +0x3f,0xc5,0x7b,0x01,0x75,0x31,0x28,0x51,0xc9,0x96,0xe0,0x3f,0xbf,0x44,0x25,0xc0,0x28,0x2f,0x50,0x28, +0x66,0xcb,0xfe,0xe7,0x8d,0x00,0x97,0xe2,0xf3,0x46,0x76,0x43,0xee,0xa2,0xcc,0xdf,0x17,0xf3,0xfc,0x55, +0x39,0x28,0x5b,0xcc,0x67,0x2b,0x72,0x67,0xeb,0x01,0x5e,0x45,0x09,0xd1,0xd5,0xa6,0xf4,0x6e,0x2b,0x3c, +0x88,0x52,0x80,0x66,0x5e,0xa2,0x54,0x92,0x07,0xe1,0xcf,0xf8,0x96,0x54,0x62,0xd3,0x1f,0x44,0xd1,0x07, +0x71,0x5d,0x80,0x28,0xad,0x05,0x24,0x09,0xf1,0xb9,0x10,0x1a,0x99,0x8c,0xd5,0x72,0x78,0x1c,0x62,0xf1, +0x48,0x68,0x2d,0xfb,0x6d,0x4b,0xa8,0x2c,0x87,0xa7,0x63,0x3d,0x44,0x4f,0xa2,0x4c,0x25,0x3c,0x16,0x01, +0xec,0x86,0xdf,0xa0,0x4c,0xab,0x15,0xf1,0x55,0x9a,0xa4,0x0d,0x79,0x81,0x89,0xef,0xe1,0x59,0x92,0xb0, +0xbb,0x19,0x9e,0x93,0x8a,0xbc,0x94,0x44,0x11,0xbf,0x69,0x09,0xa3,0x9b,0xa1,0x59,0x59,0xf7,0xe1,0xac, +0x08,0x38,0x8b,0x32,0x52,0x37,0xc4,0xd7,0xd0,0x4c,0x49,0x6b,0x7c,0xd3,0x1f,0x4a,0x25,0x98,0x2a,0x89, +0x31,0x15,0x25,0xdc,0x6e,0x85,0x26,0xa6,0x28,0x21,0x78,0x2b,0x3c,0x31,0x11,0xe6,0x29,0x71,0x8c,0xb2, +0x0f,0xaf,0x10,0xf7,0x5c,0x19,0x24,0x55,0x78,0xec,0xe2,0xda,0x24,0x8d,0x9f,0x59,0xad,0x28,0x8c,0xe6, +0x5f,0x2e,0xd5,0x68,0xc5,0x57,0xaa,0xa6,0x39,0x6a,0x3f,0x5c,0x69,0xae,0xb5,0xf8,0x56,0xc2,0xda,0xff, +0x76,0x3c,0x2f,0x99,0xd3,0xc9,0x19,0x23,0x61,0x0c,0xa3,0xab,0x53,0xcd,0xb9,0xfe,0x22,0x7c,0x65,0x08, +0xfa,0x93,0xa9,0x6f,0x4f,0x07,0x86,0xa7,0x13,0x6f,0x41,0x9d,0x91,0xb4,0x84,0x80,0xb3,0x2c,0x32,0x23, +0xe2,0x14,0x41,0xbf,0x78,0x86,0x29,0x7e,0xaf,0x50,0x15,0x96,0x49,0xf3,0x50,0xdb,0x0b,0x04,0xbb,0x5c, +0x46,0x09,0x66,0xf8,0xad,0x59,0xaf,0x44,0x3c,0x73,0x2e,0x8b,0xf7,0xfa,0x06,0xfe,0xe1,0x7a,0x2c,0x21, +0x5e,0x91,0xdc,0x18,0x42,0xbf,0x45,0x13,0x69,0xec,0x56,0x51,0xeb,0x66,0xf5,0x9c,0x7e,0x47,0x4d,0xe6, +0xd3,0xf8,0x27,0x5b,0x49,0x85,0x14,0x35,0xd9,0x8a,0xe5,0x76,0x30,0x7a,0x94,0x7c,0x6d,0x1d,0xb5,0x74, +0x1f,0xb5,0x81,0x51,0xc0,0x2c,0x80,0x00,0x2b,0xe4,0x35,0x09,0x30,0x59,0x8d,0x60,0x96,0x7b,0x55,0xa4, +0x01,0xd1,0x66,0x4a,0x15,0x69,0x4d,0x75,0x00,0xa7,0x00,0x31,0x0c,0x20,0x29,0x0d,0x26,0x2d,0x03,0x9d, +0x2f,0xa7,0x14,0x60,0xaf,0xa1,0x77,0x85,0x54,0xea,0x29,0xd2,0xa1,0xe4,0xb6,0x09,0x40,0xe3,0x9e,0x9d, +0xa0,0x28,0x7b,0x11,0xb6,0x20,0x07,0xaa,0x06,0xaa,0x6c,0x5e,0xc1,0x3f,0x68,0xc7,0x84,0x3a,0x82,0xce, +0x0d,0x0b,0x0c,0x9d,0x34,0x7e,0xdd,0x88,0x7c,0x2d,0xf2,0x8f,0xdb,0x6f,0xd4,0x8e,0x04,0xb9,0x30,0xc0, +0xd3,0xf3,0xaf,0xaa,0xd1,0x51,0x05,0x5f,0xa2,0x44,0xed,0x7f,0x88,0xcc,0x91,0x64,0xdf,0xc7,0xa0,0x82, +0x31,0x91,0xe8,0x7c,0x71,0xd6,0xc2,0x97,0x67,0xb4,0x38,0xe7,0x2e,0x96,0x8d,0xcc,0x02,0x4c,0x03,0x5d, +0xdb,0xb6,0x91,0xb6,0xbd,0x59,0x35,0xbb,0xbe,0xcd,0x99,0x4e,0x46,0x9f,0xc0,0xec,0xba,0x73,0x04,0x44, +0x06,0x57,0xd8,0x69,0x17,0x7c,0x1d,0x81,0x15,0xa1,0x3a,0x33,0x69,0x54,0x8c,0xf7,0x00,0x6e,0xd4,0xf9, +0x52,0xea,0x7c,0xb1,0x98,0xb5,0x94,0xcf,0x6f,0x56,0xf4,0x4d,0xe1,0x56,0xeb,0xf5,0x7a,0x4b,0x16,0x79, +0x78,0x61,0xe5,0xfd,0x85,0x46,0x4c,0x32,0xb0,0x7b,0xc3,0xf3,0x19,0x38,0x83,0x16,0x36,0x5c,0xed,0x19, +0x8e,0xeb,0x65,0xba,0x03,0xc3,0xd4,0xc2,0xde,0xc5,0x8c,0xa9,0xf7,0x3c,0x79,0x25,0xf3,0xaf,0xc0,0x35, +0xa2,0x9f,0x96,0x34,0x0f,0x66,0x41,0x7c,0xeb,0x04,0x79,0x4c,0xf3,0x0e,0xf7,0x14,0x4a,0xbd,0x45,0x8b, +0x62,0x77,0xe8,0xad,0x92,0x9d,0x53,0x84,0xc4,0xef,0xe9,0x98,0x2f,0x9a,0xea,0xe9,0x0b,0x3f,0x00,0x7b, +0xd6,0x33,0x20,0x74,0x54,0x73,0x69,0x91,0xd8,0x8f,0xfa,0x50,0x35,0xe2,0xab,0x0d,0x81,0x95,0x0d,0x62, +0xbf,0x70,0xef,0x4d,0xdc,0xa7,0x11,0x18,0x50,0xc8,0x8d,0x63,0x3f,0x72,0x27,0x49,0xdc,0x27,0x4f,0x8f, +0x07,0x02,0xf9,0x65,0xfc,0x87,0x45,0x03,0x1a,0x3b,0xf1,0x2d,0x4d,0x75,0xfd,0x2e,0xf8,0xc0,0x7d,0x91, +0xe2,0xa7,0xef,0x20,0x89,0x59,0xc2,0xc4,0x4e,0x38,0x1f,0x2a,0xc1,0xff,0xdf,0x6b,0x5a,0xac,0x87,0x29, +0xe4,0x37,0x8b,0x78,0x72,0xde,0x77,0xbb,0xdd,0x88,0x58,0x59,0x1f,0xdd,0x6f,0x3f,0xd7,0x4b,0x7c,0xeb, +0xb1,0xea,0x46,0x48,0xd2,0x64,0x37,0x40,0xd4,0xc4,0xaa,0x12,0x61,0xaa,0x63,0x9b,0x02,0x88,0x9e,0xef, +0xa9,0xff,0x83,0x86,0xbe,0x78,0x69,0xf9,0x3e,0xaa,0x6c,0x11,0xcb,0x96,0xa3,0x65,0x65,0x84,0x04,0x12, +0x20,0xbe,0xad,0xc5,0xdf,0x69,0xb1,0x2e,0xff,0x2c,0x2d,0xd9,0xe7,0x0b,0x2e,0x29,0xc2,0x96,0xef,0xe2, +0xef,0x6c,0x11,0x2f,0xfe,0x2e,0x1c,0xb1,0x0b,0x0b,0xf8,0x0b,0x7a,0x71,0x11,0xe1,0xfb,0x5c,0x58,0x00, +0x17,0xf7,0xb2,0xaf,0xb0,0xc4,0x97,0x7c,0x5e,0x8e,0x00,0x5c,0xee,0x8b,0xbf,0xd2,0xa2,0x8f,0x7c,0xe6, +0xea,0x76,0xf8,0xa5,0x60,0x00,0x5c,0x01,0x0a,0x5c,0x9f,0x28,0xd4,0x0a,0xc5,0xad,0x9e,0xae,0x6e,0x87, +0xb4,0xa2,0x39,0x9a,0x10,0x4e,0xf6,0xc5,0xc0,0xf4,0x0c,0x73,0xd9,0x48,0x98,0x47,0x3e,0xa2,0x81,0xe1, +0x9a,0x40,0xad,0x57,0xe1,0x40,0xf8,0x5d,0xc3,0xbf,0xa2,0xcb,0xb4,0xf4,0x8e,0x1a,0x89,0x38,0x54,0xc5, +0xae,0x58,0x99,0x36,0xc5,0x16,0xd2,0xbb,0xb4,0x7b,0xb1,0x90,0xe6,0x97,0x97,0x21,0xba,0x7f,0xbe,0x88, +0x44,0xfb,0xab,0x15,0x7e,0xa6,0x18,0x5b,0x03,0xcb,0xcb,0xb0,0x75,0xb0,0xbc,0x0c,0x5f,0x0b,0xcb,0x0b, +0xf9,0xeb,0x61,0x79,0x31,0xbe,0x26,0x96,0x17,0xc2,0x75,0xf1,0x5c,0x09,0x58,0x1b,0xcf,0x14,0x79,0x1e, +0x41,0xb8,0x46,0x96,0x97,0xa0,0x75,0x12,0x53,0x84,0xad,0x95,0x98,0x0f,0x62,0xbd,0x48,0xda,0x6f,0x8c, +0x99,0xa5,0xea,0x1a,0x28,0xaf,0xfc,0x57,0x57,0xd5,0x8a,0x5a,0x29,0x46,0xbb,0x8d,0x2c,0x27,0x68,0x55, +0x43,0xeb,0x72,0x0e,0x8a,0xf9,0x0f,0x3e,0x14,0xfe,0xa7,0x38,0x28,0x74,0x7f,0xc7,0x42,0x40,0x02,0x12, +0x89,0x3f,0x6e,0x6e,0x6e,0x46,0x56,0x04,0xad,0x3f,0x10,0x30,0x13,0x10,0x9b,0x5a,0x2c,0xd3,0x98,0xfb, +0x18,0x66,0x1e,0xe2,0x73,0x84,0x89,0xe8,0x5b,0xa5,0x62,0xd1,0x47,0x46,0x67,0x6b,0x5d,0x5d,0xaf,0xac, +0xc0,0x48,0xe6,0x3a,0x8b,0x67,0x28,0xcb,0x8a,0xc9,0x8c,0xc5,0x07,0x8e,0x33,0x98,0x30,0x74,0x4f,0xe1, +0xe1,0xc6,0x20,0x13,0xf4,0xfb,0x05,0x22,0x9e,0xbb,0x3a,0x8a,0x6c,0x63,0x3b,0x32,0x75,0xc3,0xb1,0xe9, +0x19,0x23,0xdc,0xfb,0x97,0xb7,0xf5,0x44,0x21,0x53,0xed,0xe8,0xe6,0x63,0x88,0x4d,0x29,0x28,0xa0,0xfd, +0x02,0xd1,0x2d,0xb2,0xbc,0x6f,0x13,0x44,0xf6,0xc3,0xf2,0x7c,0x2b,0xcc,0x6f,0x59,0xde,0x12,0x93,0x03, +0x0e,0x38,0xe0,0x7a,0x19,0xff,0x88,0x49,0x29,0x95,0x4a,0xdb,0x71,0xac,0x53,0x54,0xcc,0x96,0x40,0xad, +0x0a,0x3a,0xc4,0xfe,0xb6,0xc3,0xee,0x2a,0xec,0x14,0xb7,0x79,0xba,0x77,0xba,0x36,0xcf,0x61,0xd3,0xb1, +0x25,0xe2,0x54,0xff,0xb8,0x12,0x21,0x13,0x60,0x51,0x81,0x18,0x53,0x60,0x59,0xd1,0xa5,0x85,0xc2,0xa6, +0x41,0x5c,0x09,0x22,0xc0,0x65,0x05,0xc2,0x36,0x44,0x5c,0x89,0x88,0x2d,0x11,0x57,0x64,0xce,0xa6,0x88, +0x2b,0x14,0xb1,0x2d,0xe2,0x8a,0xc8,0x36,0x46,0xfc,0x77,0xc9,0xd6,0x88,0x2d,0xf0,0x1c,0xc6,0x64,0xdb, +0x23,0xee,0x7b,0xc8,0x06,0xf1,0x0b,0x10,0xf9,0xcf,0xbd,0x0d,0x5b,0x28,0xfe,0x6b,0xdf,0x52,0x89,0x97, +0xf1,0xc5,0x90,0x90,0x67,0xaa,0x3f,0xd4,0x82,0xdf,0x03,0xdd,0x1c,0x65,0x98,0xde,0x9c,0x8e,0x7e,0x66, +0x81,0x1a,0xd1,0xb7,0x11,0x08,0xc4,0x6b,0x01,0x81,0xff,0x61,0xa8,0xbb,0xae,0xda,0xd7,0x79,0xe3,0x2b, +0xc5,0x26,0x85,0x8d,0x91,0xb9,0xa6,0x1f,0xe7,0x7d,0x7c,0x71,0x43,0xe2,0xd1,0x4c,0xdc,0xdf,0x18,0x59, +0xab,0x12,0x1b,0x58,0x58,0x87,0x73,0x9e,0x58,0x88,0xfd,0x5d,0xf7,0x02,0xf1,0x95,0xbc,0xec,0xbd,0x25, +0x5b,0x7e,0x91,0xaf,0x96,0x33,0x84,0xa5,0xdd,0xbb,0x7e,0x18,0x0f,0x67,0x77,0xd0,0x4d,0x41,0xe2,0x5b, +0x59,0x9c,0x2a,0x98,0x93,0x0c,0x31,0x5f,0x3d,0xc2,0xd6,0xa3,0x5f,0x23,0x7e,0x95,0xa2,0xcc,0xa5,0xb8, +0xe3,0x51,0x6e,0x99,0x0d,0xdd,0xe7,0xa9,0x61,0xbc,0x15,0xf2,0x92,0x6b,0xc2,0x2f,0x1c,0x22,0x90,0xe0, +0xb5,0x3f,0x5f,0x51,0xc7,0x4e,0x2c,0x71,0xe2,0x28,0x33,0x05,0x29,0x86,0x01,0xfb,0x8a,0x09,0xa6,0xa2, +0x80,0xa9,0xc2,0x42,0x30,0x22,0x1a,0xf4,0x1c,0x30,0x5c,0x83,0x7e,0x00,0x1c,0x69,0xfa,0x7d,0xb5,0xb4, +0xb0,0x99,0xc0,0x67,0xb4,0xac,0xb1,0x79,0xcf,0x52,0x60,0xc5,0x2a,0xf8,0x7f,0xa4,0x0d,0x5f,0x1c,0x21, +0xec,0xcb,0x40,0x0f,0x5a,0x93,0x9c,0x4a,0xab,0x75,0x1f,0xe3,0x85,0x92,0xec,0xe9,0x55,0x21,0x58,0xa9, +0xd7,0x85,0x3d,0xe1,0x14,0xf2,0x71,0x87,0x7b,0xcc,0x14,0xe3,0xba,0xe4,0x6e,0x3f,0xc1,0x9c,0x4a,0x61, +0x0b,0xc4,0x27,0xe3,0xc2,0xe3,0xbc,0x14,0x0d,0xbe,0xce,0xed,0x78,0x85,0x3f,0xcb,0xbb,0x69,0x31,0x9f, +0x0b,0x99,0x62,0x78,0xef,0x2f,0xfa,0xb9,0xe4,0xef,0x56,0xc6,0x7e,0x8e,0x6c,0x81,0x8a,0xcf,0x71,0xdc, +0x34,0xc2,0x07,0xb9,0x52,0xb1,0xb1,0xb1,0x11,0xef,0xb6,0x08,0xb6,0x0a,0xb2,0x15,0x54,0x5a,0xc4,0xb2, +0x20,0xbf,0x24,0xd3,0x35,0x96,0x73,0x4d,0xde,0x5f,0x5c,0x47,0xf1,0x3d,0x88,0x30,0x0f,0xda,0xbb,0x71, +0xbb,0x8e,0xae,0x5b,0x2c,0xdc,0x23,0x08,0xb3,0x29,0x1b,0x56,0xea,0x51,0x8c,0x93,0x3b,0xb8,0x43,0x21, +0x71,0x62,0x2e,0x37,0x19,0xdb,0x5a,0x6c,0x4e,0x2e,0x36,0x22,0xff,0xc7,0xbf,0xf9,0xd7,0xfb,0x37,0xc3, +0x82,0x6d,0x91,0x32,0xfb,0x14,0x61,0x0e,0x91,0xe9,0x93,0x3e,0x45,0xe7,0x6f,0xee,0x93,0x3f,0x81,0xb1, +0x5f,0x22,0x33,0xb8,0xb0,0x4c,0xfc,0xd7,0x60,0x0e,0xe7,0x3e,0x05,0x93,0x38,0xf7,0x49,0x9a,0xc5,0xb9, +0x6f,0xa1,0x69,0x9c,0xfb,0x2a,0xcd,0xe3,0xdc,0x37,0x31,0x91,0x31,0x1f,0xf8,0x4c,0xce,0x7f,0x59,0x38, +0x30,0x31,0x97,0x73,0x1f,0x68,0x32,0x23,0x92,0x39,0x56,0xab,0x5b,0xa6,0xce,0x2c,0x34,0x61,0x24,0x4d, +0x06,0x79,0x4d,0x9c,0x0d,0xb3,0x8a,0xca,0xb2,0x22,0x3f,0x7c,0x4e,0x4f,0x9c,0xe3,0x55,0x32,0x33,0x64, +0x8e,0x5a,0x30,0xeb,0x2a,0x40,0xad,0xd8,0x21,0x06,0xcf,0xbf,0x26,0x6a,0x55,0xd4,0xcd,0xf4,0x8c,0x7b, +0xd0,0x98,0x88,0xc7,0x4a,0x91,0xdc,0xf4,0x96,0x24,0x59,0x7e,0x3b,0xa4,0x39,0x50,0x1d,0xc3,0xd3,0x87, +0x69,0xf1,0xc3,0x34,0x5c,0xef,0x71,0x4e,0x6b,0x79,0x0a,0x7d,0xc6,0xbf,0x78,0xac,0x3a,0x6d,0xe9,0xcd, +0x99,0xab,0xf9,0x50,0xdb,0xc2,0x2a,0xa6,0x3d,0xe3,0x25,0x65,0xf1,0x30,0x01,0xbc,0x91,0x40,0xb1,0xee, +0x22,0x78,0x8c,0xdb,0x60,0x8e,0x89,0x1f,0x08,0x9a,0xf4,0x83,0x19,0x1f,0x63,0xa2,0x0c,0xc2,0x94,0x11, +0xa9,0xa0,0x84,0x86,0x1c,0x27,0xe3,0x96,0x55,0x8a,0x8e,0x25,0xa6,0x48,0x08,0xed,0x31,0xdf,0x5d,0x7d, +0xa4,0xc2,0x30,0x6d,0xe7,0x05,0x36,0x87,0x14,0x38,0xe1,0xf7,0x11,0xea,0x30,0x12,0xbd,0x28,0x3e,0x91, +0x36,0xe4,0x44,0xb6,0x56,0xb7,0x89,0x8c,0x16,0xcc,0x5a,0x40,0x5c,0x6a,0xc7,0xb5,0xcd,0xb1,0xa7,0x2f, +0xa4,0xaf,0x98,0xb1,0xf9,0xfd,0x71,0x4a,0xc5,0xaa,0x14,0xfe,0xc0,0xa6,0x84,0xc7,0x1b,0xf8,0x2d,0xb0, +0x7d,0xec,0x8f,0xd1,0xda,0x3e,0xf6,0xc8,0xd5,0xc6,0xc2,0x0b,0xd8,0x06,0xf6,0x5c,0xd1,0x08,0x1d,0xcd, +0x01,0x1f,0x00,0xab,0xba,0x7e,0xa5,0x8f,0x32,0x25,0x56,0xd5,0x9e,0xa7,0x3b,0x8f,0x22,0xe4,0x35,0xf1, +0xbf,0x8a,0xe5,0x46,0x25,0x21,0xad,0x6c,0x3a,0x6f,0x11,0x51,0x73,0xb8,0x99,0xb6,0x90,0x4a,0x5e,0xd2, +0x59,0x2b,0xe1,0x37,0x05,0xda,0x0d,0x46,0x2b,0x63,0x18,0xb3,0x88,0x79,0xce,0xdc,0xf3,0x93,0x14,0xdb, +0xfe,0x9b,0x59,0x95,0x95,0x8b,0xa9,0x16,0x4f,0xdc,0x8b,0xa8,0x7a,0xd5,0xfa,0xcf,0x2c,0x8e,0x18,0xe8, +0x31,0xc6,0xc9,0x87,0x57,0xe2,0x28,0x7e,0xe0,0xbc,0xff,0x8d,0xea,0x20,0xe5,0x79,0xf6,0xb8,0x3b,0xd8, +0x96,0x86,0x4d,0x74,0x23,0x0d,0x9a,0xa3,0x21,0x64,0x23,0xe6,0x57,0x63,0x12,0xf3,0x10,0x4a,0x21,0xef, +0xf4,0xae,0xa3,0x3a,0xa1,0x35,0xb2,0x0a,0x91,0xcf,0xaf,0xe8,0xf4,0xfc,0x1a,0x9f,0x77,0x46,0x4a,0x6e, +0xc7,0x42,0x60,0x90,0x30,0xc7,0xdc,0xb2,0x6e,0x83,0x36,0x45,0x6d,0x12,0x8b,0xbe,0x99,0x4a,0xbf,0x38, +0xeb,0x1b,0xdd,0xbf,0x6e,0x00,0x91,0xe5,0xc4,0x5a,0x13,0x5e,0x4f,0x99,0x01,0x0a,0xf5,0xbd,0xbc,0x51, +0xd6,0x36,0xd6,0xb7,0x23,0x47,0x59,0xc6,0xa3,0x91,0xee,0x74,0x55,0x57,0x96,0x2f,0xc0,0xf3,0xc3,0xde, +0xeb,0xf0,0x3a,0x8e,0x75,0xda,0xfa,0xc5,0xe4,0x60,0x98,0xc5,0x32,0x25,0xce,0x7d,0x10,0xaa,0xfe,0xe8, +0x47,0xa4,0x94,0xe7,0xbe,0x29,0xa1,0x75,0x3a,0x17,0xb2,0x34,0x7f,0x6c,0x6c,0x01,0x13,0xc3,0xea,0x21, +0xb0,0x02,0xcb,0xff,0xd9,0xe6,0xd1,0xeb,0x1f,0xac,0x6a,0x1e,0xbd,0xa2,0xc4,0xb6,0x1c,0xfb,0x95,0x0e, +0x1a,0x61,0xc0,0x8b,0x74,0x5c,0x0c,0xbe,0xcb,0x07,0x23,0x42,0x0e,0xf0,0x0e,0xfe,0x91,0xb6,0x19,0x9e, +0x39,0x31,0xb1,0xad,0x0f,0x47,0xde,0x2c,0xd3,0xd5,0x4d,0xd3,0xad,0xba,0x03,0x7b,0xea,0x37,0xae,0xf0, +0x63,0x84,0x52,0xc7,0xfc,0x68,0x14,0x9d,0x79,0x53,0x2a,0xe5,0x7f,0xe6,0x0a,0x8a,0x1a,0x8d,0xf9,0xf7, +0x5d,0x2a,0xb4,0x94,0xe7,0x02,0x0d,0x83,0xe6,0x3d,0x9a,0x79,0xfe,0x3c,0x10,0xe6,0x3d,0x93,0x63,0x8b, +0xc6,0xc3,0x88,0xd7,0x8f,0xc6,0x92,0x38,0x7a,0xf4,0xbc,0xd6,0x76,0xf4,0xa0,0x56,0xac,0x23,0x4a,0x40, +0x12,0x75,0xc1,0x08,0xa8,0xe2,0x9c,0x2e,0x14,0xac,0xc3,0x01,0x91,0xda,0x40,0xea,0x8d,0x9b,0xfd,0x3c, +0xfe,0x91,0xce,0xfa,0xcd,0xe9,0xbc,0xd1,0x13,0x7b,0xa4,0x1e,0xcb,0xc0,0x3d,0x4b,0xb2,0x54,0x30,0x63, +0x6b,0x9a,0x8c,0x53,0x60,0xd1,0x8e,0x31,0x42,0x57,0xa6,0x53,0x05,0xcb,0x84,0x8d,0x21,0x59,0xb4,0x94, +0x8c,0x52,0x48,0xc5,0xb6,0xfa,0xbe,0x57,0xc4,0x3f,0x41,0x8b,0x6c,0xc0,0xd8,0xc4,0x92,0x8d,0x0b,0x36, +0x41,0x71,0x95,0xf0,0xb4,0xea,0x47,0xe8,0x3d,0xf0,0xe1,0x7c,0x8c,0x36,0x34,0x87,0x47,0x99,0xb5,0xc9, +0x83,0x91,0x5f,0x0f,0x9e,0x03,0x66,0x9e,0x5a,0x38,0xf3,0x9c,0x6f,0xeb,0x25,0x30,0xfe,0x91,0x63,0x27, +0x7b,0xf9,0x01,0x5f,0xee,0xc2,0x08,0x79,0x2f,0xc0,0xbc,0xe1,0x1e,0xa0,0x75,0x7d,0x48,0xee,0x0b,0x58, +0xc4,0x7d,0x11,0x5f,0x8c,0x4f,0xe1,0xe7,0xa2,0xf4,0x23,0xf4,0xbc,0x2e,0xfd,0x28,0x49,0xcf,0xf2,0xfb, +0xb2,0xf4,0xbc,0x21,0x3d,0x57,0x82,0xe7,0x7c,0xa8,0xa5,0x70,0x87,0xe1,0x5e,0x8a,0xa1,0x5f,0xa5,0xd0, +0xaf,0xf5,0xd0,0xaf,0x72,0xe8,0xd7,0x46,0xe8,0xd7,0x66,0xe8,0x57,0x25,0xf4,0x6b,0x4b,0xfe,0x55,0x0c, +0xff,0x28,0x49,0xcf,0xc1,0xb0,0x8a,0x21,0xf0,0x8b,0x21,0x80,0x8b,0xe1,0x16,0x42,0x00,0x17,0x43,0x00, +0x97,0xc2,0x3f,0xe4,0xe7,0xb2,0xf4,0x1c,0x60,0x2d,0x54,0x7b,0x5d,0x2a,0x54,0x96,0xf1,0x17,0x42,0x43, +0x39,0x54,0x6a,0x43,0x7a,0x0e,0x9a,0x0d,0x61,0x6a,0x53,0x6e,0x6a,0x33,0xfc,0x25,0xa8,0x12,0x42,0xe0, +0xbf,0xe9,0xb0,0x08,0xa7,0xc7,0xb8,0xf3,0x22,0x51,0x1a,0x5e,0x74,0x6a,0x24,0x42,0x95,0xf1,0x67,0x47, +0x22,0x64,0xbc,0xf0,0x04,0x09,0x23,0xfd,0xe8,0x21,0x12,0x3e,0x21,0xb1,0xe7,0x48,0x22,0x0b,0x27,0xee, +0x34,0x09,0x9f,0x84,0xd8,0x03,0x25,0x91,0x35,0xb8,0xf0,0x58,0x49,0x84,0x8a,0xe2,0x0f,0x97,0x30,0x0a, +0x8f,0x9e,0x2f,0x99,0x5b,0xaa,0x0b,0x4f,0x99,0x88,0x85,0x1b,0x7b,0xd0,0x24,0xca,0x46,0xe2,0x8e,0x9b, +0x88,0xd5,0x1d,0x7b,0xe2,0x64,0x6e,0xb1,0x2f,0x3c,0x77,0xc2,0x96,0x4f,0xf4,0xe8,0xc9,0x1c,0x7b,0x88, +0x3d,0x80,0x32,0xc7,0x36,0x16,0x1d,0x43,0x11,0x1c,0x25,0xf6,0x24,0xca,0x1c,0x83,0x89,0x39,0x8f,0x22, +0xd8,0x4e,0xec,0x91,0x14,0xb6,0xb8,0xa3,0xa7,0x52,0xe6,0xd8,0xce,0xa2,0xb3,0x29,0x73,0x1c,0x29,0xf6, +0x84,0xca,0x1c,0xdb,0x5d,0x7c,0x4e,0x45,0xb0,0xb1,0xd8,0xa3,0x2a,0x0b,0x85,0x48,0x98,0xd7,0x45,0x8e, +0xad,0x44,0x45,0x16,0xe5,0x8f,0x08,0x6b,0xec,0xc6,0xb0,0x0f,0x4c,0xc2,0x1d,0xd9,0x96,0x8b,0x31,0xf4, +0x4b,0x8e,0xbc,0xbe,0x07,0xbe,0x63,0x8f,0xbd,0xf4,0x7b,0xca,0x1a,0x91,0x0d,0x54,0x74,0x3a,0xee,0x41, +0x2a,0x09,0xb7,0xd3,0x4d,0x30,0x4b,0x8a,0xae,0xa2,0x83,0xb1,0x80,0xc7,0xa9,0xe9,0x74,0xcc,0xd2,0xef, +0xf6,0xf2,0xcf,0x22,0x55,0xc6,0x92,0x32,0x4b,0xbe,0x09,0xc0,0x7d,0x4f,0x9b,0x6c,0xf5,0xc7,0xa4,0x50, +0x10,0xe5,0xb3,0xcc,0x08,0x50,0x68,0xbc,0x8f,0xdc,0xbf,0x32,0xea,0xfa,0x9e,0xa8,0x51,0x37,0x5a,0x52, +0xc2,0x89,0x5f,0xfc,0x29,0xcb,0x1d,0x03,0xa1,0xa3,0xf1,0x05,0x8a,0x8b,0xf5,0xcd,0x3c,0x8a,0xab,0x2b, +0xe7,0xc9,0x72,0xf4,0xf7,0x3f,0xb0,0x2f,0xdf,0x85,0xa3,0x50,0x10,0x0a,0x4b,0xe1,0xb1,0x24,0x88,0x44, +0xd7,0xe5,0x08,0x92,0x39,0x4f,0x50,0x91,0x74,0xdf,0xe2,0x22,0xcd,0x9c,0x35,0xaf,0x84,0x92,0x59,0xa0, +0x01,0x2a,0x1f,0xca,0x2e,0xe5,0xf3,0xc1,0x16,0x3f,0x33,0x6f,0x45,0xb5,0xe2,0xa3,0x64,0x0d,0xc7,0xd7, +0xc9,0x30,0xbf,0x93,0xe4,0x4f,0x14,0xc7,0xde,0xdd,0x71,0x87,0x34,0x68,0xde,0x44,0xa5,0x52,0x59,0xd4, +0x2d,0xe2,0x09,0x54,0xba,0x22,0x6e,0x0f,0xbf,0x0f,0x39,0x61,0x17,0x7a,0x20,0xe4,0xcc,0x1b,0x85,0xad, +0x42,0xa5,0x50,0xd9,0x16,0xae,0xec,0x6d,0x4e,0x06,0x1c,0x3e,0xfa,0x95,0xa1,0x79,0x96,0xdc,0x14,0xb4, +0x1c,0x62,0x3d,0xb4,0x01,0x31,0xf8,0xce,0xb4,0x02,0x5a,0x68,0x04,0x98,0xa2,0x06,0x61,0x42,0x7c,0x5c, +0x5b,0x5b,0x5b,0x81,0x21,0xb2,0xc1,0x1c,0xca,0x1b,0x22,0x58,0x98,0x55,0xe2,0xc6,0x5f,0x3a,0xf4,0x4b, +0x19,0x9b,0x72,0xfe,0x10,0xdc,0xe9,0xf5,0xb3,0x75,0x84,0x0b,0x66,0x7d,0xff,0x21,0x98,0xc1,0x98,0xa3, +0x45,0x8b,0x69,0xc9,0x3f,0x0c,0x20,0x53,0x0f,0x90,0x4c,0xa4,0x2d,0xd3,0x50,0xf8,0x26,0x76,0x3a,0xe6, +0x43,0xd4,0xe0,0xad,0xce,0xb7,0xe0,0xdb,0xf4,0xe1,0xb7,0x31,0x87,0x38,0x60,0x62,0x7a,0x15,0x4d,0xdb, +0x78,0x8a,0x2f,0xa9,0x88,0x24,0x1d,0xe4,0x42,0x88,0xed,0x43,0x2a,0x20,0x1f,0x7e,0x2a,0x48,0x2e,0xd1, +0x27,0x69,0x85,0x4a,0x5d,0xcb,0xa7,0x3c,0x36,0x53,0x0b,0xb7,0x2e,0x29,0x48,0x40,0x66,0x90,0x61,0x86, +0x02,0xab,0x0b,0x6d,0x5e,0xb6,0xb4,0x97,0x10,0x0b,0x06,0x45,0x04,0xb4,0x22,0x81,0x24,0x9c,0x0a,0x8b, +0x5d,0x0a,0xdc,0xfa,0xf7,0x0b,0x28,0xa0,0xb7,0x2d,0x74,0x97,0x06,0xfb,0x01,0xe1,0xf2,0xe9,0xc8,0x6f, +0xe6,0xbf,0x9c,0x7b,0xdb,0xd1,0x7b,0xb6,0xa3,0x2f,0x08,0xbc,0xe3,0x58,0x40,0x0e,0x10,0xf2,0xcc,0xbf, +0xa4,0x65,0xdf,0x61,0xaa,0x24,0x64,0xee,0x90,0x09,0xe3,0x2f,0x70,0xfa,0xc6,0xb5,0xfd,0x28,0x55,0xa4, +0x25,0xc4,0x8d,0x32,0xc9,0x12,0x5b,0xaf,0x90,0x25,0xc6,0x7b,0x4b,0x0b,0x1e,0x1a,0x92,0x02,0x52,0x9c, +0x0a,0x3f,0x30,0x83,0xec,0x76,0x99,0xdc,0x60,0xec,0x3f,0x2c,0x19,0x64,0xea,0x8a,0xf3,0xcd,0x23,0x3f, +0x0f,0x91,0xc5,0x4a,0xf2,0x23,0x18,0x92,0x2f,0x1a,0xd8,0x90,0xc2,0x95,0x1f,0x63,0x3a,0xf1,0x29,0x20, +0xaa,0x07,0x64,0x8d,0xb3,0x01,0x00,0xd6,0xc4,0x00,0xcf,0x26,0x5a,0xc2,0x06,0x9e,0xd2,0x0c,0xc9,0x59, +0xf2,0xf9,0xd1,0x13,0xe6,0x5e,0x2a,0x69,0x6c,0x7d,0xa4,0xa2,0x07,0x4e,0x07,0x82,0x3d,0x07,0x5e,0xcf, +0x32,0xb1,0x67,0x5a,0x2c,0x91,0xc4,0x41,0x71,0xb4,0x19,0x07,0x09,0xdb,0x7f,0x7c,0xec,0x19,0x26,0x74, +0x01,0xf2,0x7c,0x34,0x50,0x93,0xa7,0xcc,0xcb,0x57,0x03,0x10,0x68,0xa4,0xd4,0xa3,0x70,0xfd,0x2d,0xda, +0xe1,0x28,0xa3,0xd9,0x1f,0xdb,0x03,0xdb,0x9f,0x5c,0x70,0x7a,0x56,0x5a,0xf8,0xfc,0x50,0xa5,0x9f,0xe3, +0x42,0x39,0xd1,0xc7,0x3a,0x4f,0x74,0x11,0x24,0xbe,0x90,0xdc,0x5f,0x12,0xbb,0xd8,0x14,0x0e,0xaa,0x20, +0x9f,0x89,0x1f,0x9b,0x8a,0xdf,0x42,0x0a,0xc1,0x66,0x1c,0xba,0x38,0xc5,0xf1,0xa1,0x2c,0xdc,0xc6,0x59, +0xb8,0x5d,0xc6,0xbc,0xbc,0x71,0x08,0x48,0x2f,0x43,0x4b,0xe6,0x0e,0x93,0x06,0xc5,0x9d,0x72,0x8e,0x3b, +0xfb,0x1c,0x7d,0x11,0xea,0x70,0x47,0x78,0x69,0x63,0x27,0xb3,0x0c,0xb3,0x29,0xb9,0x6f,0x41,0x5e,0xc9, +0x75,0x1b,0x24,0xa5,0x4e,0xad,0xf9,0x53,0xa6,0x63,0xc7,0x4c,0xc6,0x67,0xf0,0x34,0xae,0x1b,0xa7,0x17, +0xd3,0xfc,0xe7,0xbd,0xbe,0x8d,0xe9,0xdf,0x4e,0xda,0x57,0x83,0xd6,0x55,0x90,0xb8,0xb3,0xd3,0xac,0x63, +0x86,0xca,0x46,0xa7,0xdb,0x5e,0xa7,0x3c,0x71,0x5b,0x57,0x66,0xeb,0xfc,0xfa,0x62,0xbd,0x7e,0x73,0x78, +0x57,0xaf,0x1f,0xec,0x3e,0x14,0x46,0xa3,0x83,0x93,0xab,0xa3,0xfb,0x1d,0xf5,0xd8,0x30,0xcb,0x85,0x8d, +0xbb,0x9d,0xbd,0xe3,0xf3,0xe6,0xc9,0xfa,0x7a,0x4b,0x3b,0x3f,0xff,0xb1,0x73,0xb5,0xb7,0x3b,0xea,0x9f, +0xb5,0x75,0xab,0x69,0x94,0x66,0x63,0xb7,0x7c,0x5d,0xdc,0xb8,0x2a,0x4d,0xdc,0xcf,0x93,0x1d,0x6f,0x52, +0x3f,0x9d,0x3c,0xe4,0xae,0x1e,0x3a,0x67,0x97,0x3f,0xc7,0xa7,0x53,0xed,0xfc,0xf8,0xf3,0xe6,0x66,0x6e, +0x6c,0xde,0x17,0x37,0xb7,0xea,0x57,0x8d,0xe6,0x8e,0x99,0x2b,0xf5,0xeb,0x43,0x7b,0xf3,0xf3,0xe7,0x87, +0xcb,0xd3,0xdd,0x9d,0x4e,0xe3,0xc6,0xdd,0x37,0x1f,0x36,0x4e,0xf6,0xae,0xdb,0xa5,0xd6,0x8d,0xbd,0x77, +0xf8,0xf9,0xf2,0x67,0x71,0xfd,0xe7,0xed,0xe0,0x6e,0xd7,0xae,0xb7,0x87,0x57,0xad,0x83,0x83,0x59,0xf3, +0x73,0x79,0x47,0xdf,0x6f,0xb5,0x76,0x8b,0xa7,0xd7,0xb7,0xd7,0xc7,0xe3,0xf5,0xdd,0xab,0xe3,0xf6,0x66, +0xa7,0x3e,0xfd,0x52,0x69,0xaa,0x17,0xfd,0x7b,0xb3,0x78,0x72,0xfa,0xf3,0xeb,0x6c,0x6b,0xff,0xae,0x60, +0xef,0xed,0xe5,0x0f,0xd5,0x7a,0xd3,0xfb,0xa1,0x6f,0xf4,0xd5,0x71,0xfd,0x7a,0x3a,0xfb,0x71,0xdc,0x6c, +0x4f,0xcb,0x5f,0x2f,0xbe,0x0e,0xaf,0x9a,0x3b,0xbd,0xf3,0x0b,0xed,0xf8,0x73,0x21,0xf7,0xf9,0x67,0xbb, +0x77,0xbc,0x3b,0xe8,0xaa,0xdd,0xbd,0x53,0xfb,0xeb,0x49,0x7d,0xef,0xe2,0xec,0xa1,0xd3,0x37,0x72,0x6b, +0x3b,0xb7,0x9f,0xcf,0xfa,0xd7,0x95,0x56,0xce,0xdc,0xdf,0xdb,0x3d,0x3c,0xed,0x94,0x36,0x2a,0xa5,0x9d, +0x5d,0xa3,0x32,0xb0,0xf6,0x0b,0x6b,0xb9,0xc2,0xda,0x56,0x6e,0xbf,0xd8,0x3f,0xc9,0x9d,0x69,0xf9,0x93, +0xdc,0xcf,0xb5,0x2f,0xa7,0xa7,0xf5,0x9b,0xcf,0xe3,0xf3,0x61,0x7f,0x58,0x3f,0xae,0xdf,0x95,0xaf,0x7a, +0xb9,0xe2,0xda,0xd7,0x2d,0x37,0x4f,0x79,0xf7,0xda,0x57,0xd7,0xa7,0x17,0x9f,0xcb,0xcd,0xdb,0x83,0x83, +0x5a,0x4a,0x3e,0x76,0xea,0xe8,0x23,0x5d,0x45,0x42,0xe1,0x4f,0xdb,0xf2,0x86,0x73,0x54,0x25,0xf7,0xe9, +0x9c,0xf3,0x3d,0x58,0xce,0x44,0xa1,0x32,0x95,0x1c,0xe1,0x8b,0xb7,0x26,0x12,0x4c,0xab,0xb8,0x73,0xd5, +0xda,0x34,0x2d,0x7c,0x61,0x11,0x91,0x9c,0xdf,0xee,0x9d,0x7f,0x69,0x4c,0xaf,0x77,0x3b,0x57,0x17,0xf5, +0xd6,0xf4,0xb0,0xbc,0x55,0x29,0x5e,0x1d,0xf6,0xf6,0xeb,0xe5,0xfa,0xf9,0x8f,0xba,0x71,0x51,0xbf,0x52, +0x2f,0xed,0x96,0x35,0xed,0x37,0x0a,0x9d,0x9f,0x9b,0x9b,0xf7,0x6b,0xbd,0xfa,0x99,0xb3,0xb9,0xd9,0xad, +0xb4,0x5b,0x9d,0xbc,0x3e,0x99,0xb6,0x6f,0xb6,0x26,0xad,0x87,0xbd,0xab,0x71,0xfe,0xac,0x50,0x36,0x6f, +0x8e,0xda,0xa5,0xdd,0xf2,0x7e,0x6b,0xc3,0x31,0xc7,0xfd,0x93,0xab,0xf2,0xee,0x7d,0x7d,0xa3,0x35,0x6d, +0x6a,0x0f,0x75,0x75,0x36,0x1c,0x0d,0xef,0x8d,0xb5,0xc1,0xb1,0x73,0xfc,0xa3,0x7d,0x77,0x95,0x9f,0x16, +0xaf,0xd7,0xb7,0xfa,0xa7,0x3f,0xb6,0x4e,0xfb,0x5e,0x13,0x1a,0xdc,0x19,0xec,0xab,0xb3,0xcf,0x85,0x4e, +0xbb,0xdd,0x9d,0xce,0x3a,0xc7,0x5b,0x07,0xb7,0xa3,0xfd,0x62,0xe3,0xb0,0x63,0x0f,0x6f,0xcf,0x4f,0x7e, +0x3e,0xc0,0xa3,0xe6,0x9e,0xaa,0xeb,0x67,0xf9,0xcb,0xc6,0xad,0x73,0xd5,0x1b,0x77,0xbf,0x36,0x4f,0x37, +0xb7,0x7a,0xd3,0x9b,0xa6,0xea,0xf5,0x72,0xb9,0xf5,0xe6,0x5a,0x7d,0xeb,0xb3,0x6e,0x78,0x37,0xa6,0x7b, +0xa8,0xaf,0xd3,0xb8,0x1b,0x87,0x17,0x57,0xe5,0x96,0x73,0x77,0xd8,0xef,0xf7,0x6b,0xb1,0x13,0xc6,0xfe, +0xc9,0xdc,0x4b,0xc7,0x6b,0xe3,0x54,0xe7,0x20,0x1c,0x2f,0xac,0xea,0xfb,0x3c,0x8c,0xe5,0x3b,0x0c,0x4e, +0x55,0x17,0x23,0xa7,0xa6,0x37,0x52,0x0b,0xa7,0x98,0x69,0x3b,0x21,0x31,0xbc,0x84,0x22,0x7a,0xbd,0xbf, +0x92,0x24,0x86,0x77,0x9c,0x6f,0x5c,0x7d,0x39,0x19,0x14,0xf7,0x77,0xcf,0xeb,0xfd,0x9d,0xab,0xba,0x95, +0xd7,0x0b,0x93,0x83,0xd3,0xd2,0x8f,0xbe,0x7e,0x74,0x7c,0xd5,0xd0,0x8f,0x87,0x85,0x92,0x56,0xaa,0x1f, +0x6b,0xf7,0xf7,0x8d,0xdb,0x93,0x69,0x69,0xa7,0x9f,0xeb,0xdd,0xd5,0x0f,0xc7,0x3f,0x9a,0x1b,0xb9,0xbb, +0x8a,0x36,0xda,0x3c,0x1b,0x4c,0x5b,0xcd,0xc6,0xe4,0x66,0xfd,0xe4,0x61,0x70,0x59,0x58,0x1b,0x7b,0x85, +0x69,0xa1,0x5d,0xae,0xb8,0x5f,0x7b,0xea,0x86,0xd1,0x74,0x6e,0xbb,0xdd,0xe6,0xde,0xf5,0x74,0xd7,0x36, +0x07,0xdd,0xe9,0xd7,0xc9,0xd7,0xb3,0xc1,0x99,0xdb,0x69,0x6e,0x7c,0x99,0xee,0x75,0x1a,0xa7,0xbb,0x46, +0xb3,0x71,0x74,0xd0,0x6c,0x8d,0xd6,0x2f,0xcb,0xd7,0x07,0x8d,0x93,0xfc,0xb4,0x62,0x1f,0x4c,0xb7,0x8a, +0xa7,0x46,0x7f,0xb6,0xde,0xbf,0xfa,0x3c,0x35,0x8a,0xc3,0xcd,0xbb,0x93,0x41,0xdb,0x68,0x94,0xb4,0x7e, +0xab,0x9e,0xeb,0xdd,0x4e,0xc7,0xbb,0x7b,0x5f,0x2a,0x6b,0xe7,0x15,0x6d,0x63,0x4d,0xb7,0x7a,0x8e,0x3e, +0xc8,0xe7,0xda,0xbb,0x47,0xbd,0x35,0xb5,0xb8,0x73,0x5d,0xd0,0xaf,0x80,0x17,0xd4,0x5f,0x47,0x0e,0x95, +0x0e,0xfe,0x11,0x53,0xcf,0x74,0xa8,0x39,0x5a,0x10,0x67,0x91,0xe7,0xe2,0x97,0xe3,0x88,0x62,0x00,0x8a, +0x07,0x12,0xc5,0x3f,0xd3,0xc8,0x1a,0x96,0x11,0x46,0xaf,0x17,0xa6,0x0c,0xbf,0xf7,0x05,0x02,0xe5,0xad, +0x29,0x23,0x2c,0x51,0xd6,0xf2,0x42,0xa2,0x1c,0x4d,0xb7,0x72,0x5a,0xae,0xee,0x9e,0x3b,0xfd,0x5d,0x43, +0xad,0x9f,0x5f,0xfe,0xdc,0x58,0x9b,0xe4,0xbe,0x16,0xaf,0xcd,0xdc,0xb4,0x72,0xbc,0xb3,0x3f,0x3d,0xba, +0xdf,0xb5,0x8f,0xef,0x66,0x5f,0x4f,0xd6,0xbc,0x5c,0xa7,0x98,0x1b,0xe7,0x7e,0x7e,0xfe,0x61,0xf7,0xf2, +0x83,0x83,0xe6,0x41,0x73,0x54,0xb9,0x6c,0xb8,0xf5,0xba,0xda,0x58,0x3f,0x3b,0x3d,0x1b,0xff,0x98,0x35, +0xef,0x2b,0xc3,0x8d,0x9b,0xcb,0xc6,0xf5,0x7a,0x73,0x74,0xf1,0x23,0xd7,0x39,0x9c,0x5c,0x6a,0x4d,0x67, +0xab,0xeb,0x1c,0xee,0x17,0xa6,0xd6,0x4d,0x7b,0x6c,0x74,0x3d,0xb3,0xb1,0x65,0xac,0x95,0xef,0xda,0x17, +0xd3,0x62,0xbd,0x31,0xdd,0x69,0xed,0xad,0x0d,0x7f,0xd8,0x93,0xee,0x99,0x36,0xbd,0xb6,0x1d,0x75,0x58, +0x80,0xe1,0x17,0xea,0x9f,0xcf,0x6f,0x06,0x50,0x64,0xbd,0x71,0xb6,0x51,0xef,0xde,0xed,0xf7,0x5a,0xfa, +0x0f,0xfd,0xe0,0x56,0x6b,0x19,0xfb,0x5a,0xfd,0xeb,0xe8,0x60,0xaa,0x39,0x7b,0x37,0xcd,0x9f,0x95,0x53, +0xb3,0x37,0x69,0xff,0xdc,0xe9,0x9f,0x9d,0x1e,0xda,0xda,0xa9,0xd9,0x2e,0xdf,0x1d,0x75,0x4f,0x8f,0x2b, +0x47,0xc7,0xad,0x9d,0xca,0xe6,0xcf,0xfa,0x49,0xfe,0xca,0x5b,0xdf,0xfc,0x5a,0xbf,0x55,0xa7,0xe7,0xfa, +0xb4,0xb0,0x75,0xf7,0x65,0xb6,0xb3,0xbb,0xf9,0xa3,0xde,0xee,0x97,0xee,0xbe,0xce,0x4a,0xe3,0xc3,0x76, +0xdf,0x1e,0x4c,0x36,0xa7,0x6b,0xe7,0x5b,0x47,0x95,0xc9,0xe5,0x59,0xe5,0x6b,0xff,0x6c,0xa7,0x77,0xb6, +0x7e,0x5b,0xea,0x14,0xd6,0x76,0x1a,0xfb,0xb7,0x0f,0x67,0xfb,0x4e,0x7e,0xe3,0x2c,0x77,0xbf,0x3e,0xeb, +0xad,0x39,0x05,0x90,0x91,0x46,0xfe,0x5c,0x7d,0xd8,0x75,0x8b,0x47,0x3b,0x83,0xd3,0x8b,0xe6,0xa4,0x31, +0x3c,0x9c,0x3e,0xd4,0x5b,0xf5,0xb5,0xd2,0x71,0xf9,0xee,0xe6,0xe1,0xf4,0x6e,0xd8,0xfd,0x0d,0xc9,0xb2, +0x4c,0xa4,0xc8,0x24,0xb2,0xaf,0x5a,0x9a,0xa9,0xff,0x95,0xf4,0xf1,0x90,0x97,0x34,0x8e,0x83,0xc3,0x5d, +0xe3,0xfe,0xeb,0x61,0x7d,0xc3,0xd4,0x0f,0x8e,0xbe,0x0e,0x1a,0xfb,0x47,0x57,0xfd,0xdb,0xfb,0x1f,0x37, +0xe6,0x48,0x3d,0x1f,0x7d,0x6e,0xdf,0xf5,0xa7,0xee,0x79,0x6b,0xe3,0xc8,0x1a,0x6d,0xe8,0x77,0x47,0xcd, +0xe9,0xf1,0xc1,0x8e,0xe3,0x5e,0x1a,0xee,0xde,0x81,0xda,0x5c,0x3f,0xbe,0xff,0xbc,0x55,0x98,0x69,0x7d, +0xef,0xb0,0x68,0x58,0xad,0xdd,0xdb,0xee,0x7a,0xc9,0x2d,0xfc,0x78,0xe8,0xee,0x9b,0x9b,0xbd,0x59,0x77, +0x47,0x3f,0x1a,0x4c,0xf6,0x7e,0xac,0xaf,0x9d,0x6d,0xec,0x3b,0x3f,0x4f,0x47,0xda,0xcf,0x8b,0xab,0x86, +0xb9,0xe3,0xf4,0x1e,0x40,0xb7,0xeb,0x1f,0x1e,0x1e,0x78,0xd3,0x83,0xc6,0x4e,0xf7,0x40,0x6f,0xf5,0x4f, +0xea,0x25,0xfd,0xe8,0xc7,0xe9,0xcd,0x5d,0xbb,0xd8,0x3a,0xbd,0x3d,0x5f,0x9b,0xdd,0xd6,0x35,0x73,0x67, +0xcb,0x39,0xd8,0xdd,0x38,0x51,0xef,0x1e,0xf6,0x0b,0xf9,0xcd,0x96,0x69,0xdd,0x35,0x0a,0xf6,0xc1,0x97, +0xaf,0xd6,0x4e,0xe5,0x87,0xae,0x5b,0x47,0xa3,0x93,0xba,0x33,0x56,0xbd,0x7d,0xf7,0xf6,0xe4,0x74,0x36, +0x2b,0xaf,0x35,0xac,0xf3,0x8b,0xf5,0xdc,0x64,0x92,0x3b,0xa8,0x6c,0x7a,0x17,0xa5,0x82,0x5b,0x2c,0x7f, +0x6d,0x37,0x07,0x76,0x73,0xeb,0xb3,0x5b,0xd6,0xd6,0x36,0xbb,0xe3,0xb2,0x5b,0xea,0x3c,0x1c,0x55,0xd6, +0x7a,0xc7,0x9d,0x96,0xf7,0xe3,0xc8,0x9c,0x55,0xf6,0xef,0xb5,0x69,0xeb,0xea,0x78,0xda,0xa8,0xb7,0x8c, +0xcd,0xa3,0xce,0x56,0xa3,0xbb,0x71,0x50,0xa4,0x49,0x6e,0x99,0xbb,0x97,0x77,0x6d,0x50,0x2e,0x9a,0xcd, +0xe5,0x73,0xbc,0x54,0x83,0x0f,0x29,0xdb,0x31,0x46,0xdc,0xfa,0x32,0x9d,0x5a,0x6c,0x4c,0xce,0x11,0x47, +0x93,0xbc,0x65,0x7f,0xa5,0x70,0x19,0x08,0xa5,0xf4,0xaa,0x78,0x3e,0x55,0x4b,0x7b,0xc7,0xf5,0x59,0x73, +0xed,0xe2,0x61,0x72,0x96,0x6f,0x4f,0xf6,0xd5,0xe2,0xe4,0x38,0x57,0xbf,0x2a,0x9f,0x0e,0x26,0x97,0xee, +0xd7,0x7e,0xeb,0x74,0x6f,0xe3,0x68,0x54,0xda,0xaf,0x3c,0xcc,0x66,0x87,0xf5,0xc9,0xc6,0x66,0xa9,0x60, +0x1d,0x7d,0xb9,0xb9,0x98,0x5e,0x1c,0xfe,0xfc,0x79,0x62,0x3a,0xf5,0x62,0x73,0xdc,0xf8,0x59,0x9f,0x5e, +0x7f,0xb9,0x39,0x3e,0x59,0xef,0x1f,0x1c,0x1e,0x77,0xeb,0xe7,0x96,0x79,0x67,0x9a,0xbb,0xde,0xf0,0x3c, +0x77,0xdd,0xa9,0x5f,0xb8,0x8e,0xed,0xb6,0x2b,0xfa,0xa1,0x73,0x76,0x39,0x2c,0xd6,0xbb,0x57,0x6a,0x79, +0xef,0xdc,0x3c,0x69,0x68,0xad,0x7b,0xa7,0xd7,0x6c,0xdf,0xe5,0x0f,0x77,0x7e,0x9c,0x0e,0xbe,0x36,0x0f, +0xb7,0xda,0xf5,0xf2,0xfd,0xe6,0xbd,0xbd,0xf7,0xc3,0x9e,0xd9,0xa5,0xbd,0xb1,0x57,0x2a,0xf4,0xb4,0xad, +0x8d,0xd2,0x43,0xae,0xdf,0x3a,0xfc,0xd9,0xfe,0xda,0xdd,0x33,0xbb,0x3b,0xe3,0xe9,0x0b,0x05,0xc8,0x2a, +0xab,0x94,0x39,0x17,0xe6,0x66,0xe2,0x02,0x6b,0xfe,0x3d,0x6b,0xf5,0xe6,0xec,0xf8,0x66,0xa3,0x75,0xdc, +0xb8,0x68,0xdd,0x17,0xcf,0x3e,0x5f,0xef,0x99,0xf5,0xe2,0xc0,0x73,0xa7,0x33,0x73,0xe6,0x96,0x1f,0xee, +0x40,0x79,0x1b,0x5d,0x54,0xfa,0xd7,0x9f,0x3f,0x0f,0x47,0x7d,0xf3,0xd0,0x33,0x2f,0x07,0x47,0xe5,0xe9, +0xac,0xd5,0x79,0xb0,0x3e,0x1b,0xc7,0x7b,0xfa,0xd1,0xc3,0xd9,0xd9,0xf4,0xf8,0x41,0x87,0x3f,0xbb,0x0f, +0xcd,0xcd,0x5b,0x4f,0x2d,0x3b,0xd6,0xcf,0xdb,0x91,0x5a,0x6a,0x5e,0x3a,0xf9,0xfb,0x5e,0xf3,0xa6,0xd4, +0xb1,0xc7,0xb9,0xcd,0x8b,0xe9,0xce,0xd9,0xc3,0xb1,0xb1,0xde,0xdb,0xca,0x5d,0x68,0x17,0xc5,0xbb,0xc3, +0xf5,0xdb,0xf3,0xfa,0x4e,0xfe,0xfe,0x62,0xf8,0x23,0x97,0x07,0x8e,0x3e,0xbb,0xd6,0xdb,0xe7,0xb7,0xbb, +0x66,0xfe,0x6c,0xba,0xb7,0xbb,0xb3,0x77,0x6e,0xef,0x4e,0xd7,0x8c,0x1b,0x6d,0x7a,0x32,0xbb,0x5e,0x6f, +0xe4,0xef,0xba,0x4d,0x6f,0x73,0xb0,0xbb,0x33,0xb8,0xb9,0xbd,0xd2,0x1f,0x4a,0xa7,0xa7,0x77,0xeb,0xa7, +0xd3,0xf2,0x65,0xe1,0x02,0xd4,0x88,0x3d,0xb5,0x3b,0x9c,0xfd,0xac,0x5f,0x9b,0xc0,0xde,0x77,0x0e,0x9b, +0xa7,0xc0,0xfd,0x2f,0xca,0xe7,0xbd,0xc9,0x56,0x4e,0xfd,0x0a,0x0b,0xef,0xe8,0xab,0x37,0x5b,0x2b,0x0f, +0xf6,0x76,0xd6,0x3b,0xa3,0xd9,0xc3,0x91,0xfb,0x73,0x6b,0xd2,0x6e,0x5a,0xa6,0xfe,0x75,0xf3,0xe1,0xf4, +0x60,0xbd,0xb4,0x76,0xfe,0x73,0xeb,0x6c,0x7c,0xf1,0x65,0xed,0xfc,0x68,0xd4,0xa8,0x7c,0x39,0xbb,0x38, +0xbf,0xbd,0x6d,0xfc,0xb4,0x07,0x2f,0x5b,0xab,0xcb,0x67,0x5a,0x28,0x07,0x01,0x5f,0x8e,0x3a,0x2d,0x7e, +0x9c,0xdf,0x34,0xcf,0x32,0xd3,0x1b,0x43,0xeb,0xeb,0x5e,0xc8,0x2b,0x16,0x1c,0xac,0xad,0x32,0x5f,0x26, +0x7a,0x35,0xdf,0xab,0xaa,0xba,0x3c,0xdd,0x03,0x96,0x2a,0xf0,0xb3,0x33,0xb2,0x0e,0x5a,0x4e,0xf9,0xb0, +0x56,0xf2,0x0b,0x4f,0x09,0x45,0x68,0xb4,0x48,0xfe,0x7b,0xc9,0x09,0x5c,0x78,0x0a,0x43,0xcc,0x7f,0x11, +0x6b,0x8a,0x9c,0xc8,0x65,0x90,0x46,0xd2,0x50,0x08,0xe8,0x68,0x2c,0xe8,0x52,0x8f,0xf1,0x9e,0x88,0x0e, +0x06,0x3a,0x9a,0xed,0x68,0x9e,0x87,0x07,0x5c,0x96,0x32,0x8d,0x87,0xbf,0x6c,0x21,0xb4,0xd2,0x6c,0xf9, +0x8d,0xf3,0x7c,0x60,0xcb,0x26,0x52,0xfa,0x46,0x9e,0x8e,0x2e,0xf3,0x1f,0xac,0x34,0x05,0x08,0x11,0x67, +0xda,0x5d,0xe0,0x3b,0x30,0x62,0xc3,0xd9,0xee,0x99,0x36,0x74,0x40,0xd1,0x30,0x21,0xc4,0x73,0x8f,0x52, +0x86,0xd0,0x80,0x6e,0x7f,0x7a,0x62,0x27,0xb7,0xe6,0x0f,0x6b,0x05,0x5b,0x40,0xac,0x4b,0x25,0x5b,0x28, +0xbb,0x82,0x83,0x54,0xe8,0x34,0x99,0x8c,0x2f,0xe1,0x5d,0x0d,0xcd,0xc4,0xc6,0xc6,0x46,0xb8,0xd4,0x29, +0x94,0x01,0x89,0xf2,0x5b,0xc8,0x65,0x71,0x3f,0xf3,0x95,0x63,0x4c,0xdf,0xe7,0x3c,0x5a,0xe1,0x63,0xbe, +0x32,0xa0,0x4d,0x42,0xea,0x63,0x68,0x0e,0x50,0x8f,0x96,0x0e,0x4a,0xcb,0x7d,0xc7,0x2c,0x03,0x2a,0x8d, +0x90,0xce,0xcd,0x0f,0x07,0xb4,0x22,0xe4,0x68,0x39,0xf0,0xa9,0x67,0x36,0x16,0x0a,0x51,0x2c,0xc5,0x37, +0x44,0x03,0xdc,0xbb,0x00,0x17,0x86,0xe6,0x38,0x98,0x7c,0xd8,0x49,0x8b,0x21,0x9c,0x39,0x3a,0xa6,0xdb, +0x7f,0x5c,0x4e,0x09,0x22,0x3f,0x53,0xfc,0x69,0x3d,0xb1,0xf7,0xbf,0xa8,0xb3,0xd0,0x89,0xb3,0x70,0xbf, +0x71,0x9f,0x18,0x91,0x48,0x07,0xd0,0x42,0x30,0xe4,0xc3,0x7d,0x44,0x1b,0x6c,0xd8,0xf7,0x71,0x24,0xb3, +0xee,0x27,0x66,0x5a,0x91,0x51,0xcd,0x1d,0x29,0x88,0xa1,0x19,0x69,0x95,0x2c,0xa4,0x9a,0xe5,0x8b,0x43, +0x22,0x26,0x36,0x9c,0xc7,0x28,0x09,0x2c,0xc0,0x28,0x2d,0x21,0x25,0x5c,0x75,0xe1,0x82,0x72,0xbb,0xab, +0x93,0xe8,0x02,0x4e,0xfd,0x2c,0x89,0x6e,0x04,0xaa,0x9e,0x40,0x4b,0xd9,0xe7,0x1b,0xf4,0x54,0x8a,0xc5, +0x92,0x6f,0x9a,0x22,0xb6,0xfc,0x85,0x55,0x47,0x6f,0x65,0x7b,0xe1,0x04,0x4b,0x2b,0xfc,0x15,0x3a,0x07, +0xdd,0x31,0x04,0x8a,0xc7,0x39,0xdd,0x55,0x61,0x9e,0xdd,0xe4,0x0d,0x52,0x9d,0xcc,0xc6,0xf1,0x75,0xeb, +0xba,0x7e,0xde,0x6a,0xe4,0x7a,0xa5,0x2d,0x5d,0x3d,0xbc,0x1a,0xe3,0xfb,0xe6,0x97,0xc6,0xc1,0xcd,0x17, +0x2c,0xeb,0x5e,0xc2,0x5f,0x47,0xad,0x69,0xab,0x3e,0x1c,0x4d,0xe9,0xc2,0x9d,0x46,0xe9,0xe2,0xf0,0xf2, +0xea,0x6a,0xbf,0x74,0x7e,0x7b,0xd1,0xd8,0xe9,0x7f,0xde,0xd2,0x3e,0x6b,0xc7,0xd4,0x87,0x99,0xbf,0xb8, +0x1e,0xe4,0xcf,0x8b,0x5b,0x5e,0xe7,0xe6,0x7a,0xac,0xd5,0x41,0xe5,0x1f,0x5e,0x0f,0xb4,0xbd,0xeb,0xbb, +0x83,0x7d,0x6d,0xa4,0xed,0xf5,0xfb,0x17,0x79,0xf3,0xe4,0x6a,0x57,0x6f,0xec,0x0c,0xc8,0xbe,0xba,0x68, +0x5f,0x5d,0x34,0xae,0xeb,0x3f,0xbe,0xdc,0xe6,0x7e,0x9c,0x4d,0x0f,0xea,0xd7,0xb7,0x17,0xbd,0xad,0x9d, +0x69,0x63,0x6d,0x32,0xcd,0xdd,0x6f,0x4c,0x8e,0x2f,0x0b,0x71,0x0a,0x9e,0xc2,0xa4,0x86,0x22,0x76,0x92, +0x19,0xae,0x6c,0xce,0x3b,0xa3,0x7b,0xad,0x91,0xcd,0xb1,0x10,0xee,0xc3,0xdb,0xa8,0xbc,0xa1,0xa1,0xdd, +0x31,0x4c,0x3d,0xaa,0x00,0xcc,0xa5,0x70,0xe3,0xbd,0x2c,0x5d,0x38,0x74,0x87,0x02,0x81,0x11,0x64,0xff, +0xa6,0x5d,0x77,0xb1,0xb0,0xca,0x73,0xdb,0x34,0xfe,0x89,0x07,0xa9,0x86,0xb4,0x70,0x22,0x6a,0x4a,0xfc, +0xde,0xe4,0x92,0x6c,0x8c,0xd1,0x40,0x6b,0x7e,0xa1,0x48,0xc4,0xab,0x2f,0x32,0x49,0xf6,0x17,0x9d,0xc5, +0x12,0x19,0x26,0xa2,0x3b,0x0e,0x91,0xe0,0x30,0x7f,0x5d,0x14,0xd8,0x36,0x7a,0xf4,0x44,0xf6,0xc7,0x70, +0x0a,0x8c,0xf5,0xf9,0x14,0x18,0x6c,0x73,0x66,0xc9,0x59,0xed,0xc5,0x59,0x63,0xe4,0xd8,0x93,0xb8,0xf0, +0x49,0x7f,0x87,0xab,0x54,0xa4,0x4d,0x3b,0xb6,0x57,0xf7,0x71,0xee,0x76,0x8d,0xd0,0xce,0x09,0x05,0xba, +0x0c,0x8a,0x8f,0xe1,0x8b,0x1f,0xb2,0x23,0xd5,0x92,0x4e,0xa0,0xb1,0x8d,0x09,0xa6,0x7b,0x45,0x8e,0x50, +0x88,0xf8,0x0c,0x29,0xb9,0x1f,0x9e,0x65,0x95,0x3c,0x57,0x6c,0x74,0x03,0x30,0x31,0xe7,0x22,0x1c,0xc4, +0x6d,0x1d,0x01,0x13,0xce,0xfb,0xdb,0x5f,0xac,0x8a,0x12,0xb9,0x5e,0xe2,0x29,0x3b,0xb4,0xb5,0xb1,0xa9, +0xa7,0xb3,0xe2,0x62,0x13,0x9e,0xbd,0x9f,0x2e,0x9d,0x19,0x8f,0x30,0x75,0xa6,0xfe,0x3d,0xcd,0x66,0x93, +0x97,0x0d,0x0f,0x83,0xa7,0x44,0x99,0x9f,0x01,0x99,0x2a,0xd9,0xf1,0x7c,0xb6,0x1e,0xe7,0x48,0x06,0xfd, +0x62,0xa1,0x4f,0x22,0xd7,0x09,0x61,0x0e,0x54,0x1a,0xe8,0x36,0xd2,0xe9,0x7b,0x98,0x27,0x0d,0xaa,0x00, +0x65,0xba,0xf2,0x6c,0xe4,0x03,0x3d,0x66,0xb3,0x3c,0xf2,0xa2,0xfa,0x01,0x0f,0xa8,0x80,0x62,0x61,0x67, +0x60,0xa6,0x1c,0x92,0xe1,0x7c,0x9d,0xcd,0x65,0xa5,0x0d,0xab,0x11,0x45,0x58,0x9b,0x04,0xbb,0xeb,0xe1, +0x7d,0x30,0xf1,0x51,0x0c,0x68,0x0b,0x48,0x1d,0x15,0x25,0x05,0x9e,0x5e,0x94,0x68,0x66,0xa8,0x05,0x05, +0xda,0x8a,0x5c,0xba,0xc2,0x3f,0x90,0x3f,0x31,0x3c,0xc1,0xd1,0x9b,0x09,0xb2,0xc4,0xb6,0x1e,0xa3,0xbe, +0x4c,0x5a,0xa3,0x54,0x1f,0xe6,0xd7,0x19,0x1a,0x96,0x4a,0x09,0x35,0xfa,0xfe,0x91,0x76,0xff,0x75,0x6c, +0x06,0xcb,0x20,0x52,0xbc,0x97,0x0f,0xed,0x40,0x36,0xed,0xb1,0x63,0x00,0x87,0x3d,0xd1,0xa7,0xb1,0x97, +0x9d,0x20,0x88,0x73,0xcb,0x22,0xbb,0x20,0xdf,0xe5,0xfa,0x28,0xe2,0xc7,0x8f,0x65,0x11,0x21,0xd2,0x12, +0x1c,0xab,0x32,0xe7,0xc3,0x17,0xb2,0x39,0x9c,0x2b,0x13,0xc8,0x5c,0xf5,0xaf,0xd0,0xf0,0x4f,0x6c,0xe2, +0x6c,0x50,0xb4,0x53,0x5c,0xf8,0x91,0x5c,0x41,0x1c,0xd8,0x17,0x01,0x7d,0x23,0x40,0xac,0x48,0x7f,0xda, +0xe9,0x67,0xba,0xa6,0xae,0x82,0x48,0x16,0x6f,0x74,0x33,0x63,0xe9,0xde,0xd4,0x76,0xee,0x42,0xef,0xdc, +0xee,0x40,0x67,0x4b,0x4d,0xe4,0x24,0x55,0xf1,0xbd,0xff,0xd3,0xd1,0x3b,0xb6,0xed,0x49,0x3f,0x81,0x15, +0x58,0x94,0x68,0x44,0xbc,0xe9,0x75,0x90,0xa5,0x81,0xb4,0xf1,0x5f,0x81,0x65,0xe6,0x01,0x1e,0x5c,0x98, +0x97,0xae,0x67,0x63,0x06,0x53,0xfe,0x81,0xaf,0xdc,0x90,0x5d,0xda,0xcd,0xe7,0x49,0x8a,0x89,0xc4,0xb5, +0x9a,0x36,0x07,0xa7,0x3a,0x32,0xee,0xf4,0xa0,0x15,0x18,0x5c,0x77,0xa8,0xc9,0x00,0x43,0x25,0xf9,0x27, +0x80,0xd8,0x33,0xfa,0x21,0x08,0x11,0x17,0xd6,0x3c,0x80,0x08,0xc8,0x78,0x34,0xff,0xde,0xd1,0x5d,0x00, +0x5c,0x97,0x00,0xc7,0x33,0xcf,0x91,0x9f,0x19,0x71,0x2e,0x39,0x3a,0xbe,0x4c,0xc7,0xb1,0xa7,0xae,0x1e, +0x09,0x4a,0xe9,0x46,0x87,0x69,0x52,0x8e,0xd1,0xb9,0x09,0xc0,0x4f,0xee,0xd4,0xf0,0xba,0x03,0xff,0x5b, +0x4c,0x4b,0xdb,0x11,0xae,0xcd,0xea,0x0e,0x01,0xe8,0x39,0xf4,0xd1,0xcb,0xb9,0x6e,0x10,0x2b,0x2e,0xb0, +0x4f,0xff,0xc5,0xd4,0xe8,0x19,0x78,0x43,0x97,0x15,0xea,0xad,0xd7,0xab,0x84,0xe0,0x7e,0xc9,0x54,0x70, +0x74,0x2c,0x42,0x8f,0xcc,0xfd,0x30,0x0a,0x81,0xb1,0x63,0xae,0x21,0x47,0x45,0x0b,0x71,0x0b,0xfe,0x4d, +0xba,0xed,0x89,0x34,0xfc,0xf8,0x95,0x29,0x82,0x3d,0x42,0x3c,0x75,0x13,0x19,0x1b,0xd8,0x4f,0xa4,0x70, +0x3c,0xe7,0x15,0xeb,0x1b,0x3d,0xa1,0xa1,0x82,0x06,0xb8,0x77,0xba,0x63,0x0e,0x76,0xeb,0xf5,0xab,0xfa, +0x61,0x6b,0xa7,0x7e,0xfc,0x70,0xfc,0x70,0x74,0xfa,0xe0,0x96,0xb6,0x72,0x78,0xdb,0x61,0x6e,0xb6,0x9f, +0x6b,0xe6,0xcb,0xbb,0xd7,0xbb,0x27,0x3b,0xe7,0xd7,0x8d,0xdd,0x63,0x63,0x7d,0x5a,0x07,0xed,0x13,0x3d, +0x95,0x6b,0xe7,0xe7,0xbb,0xcd,0x7e,0x7d,0xa7,0xce,0xaf,0xbd,0xa4,0x36,0x40,0x59,0x3d,0x3b,0x9c,0x9d, +0xfd,0xec,0x8e,0x4f,0x0e,0xbc,0x59,0xf3,0xea,0xd0,0x3e,0x6f,0xd8,0xf9,0xfa,0xc9,0xc1,0xfd,0xe8,0xcb, +0x69,0xd7,0xbb,0xdd,0x57,0xcf,0x47,0xb7,0x77,0xc6,0x7e,0xef,0xb8,0xd8,0xbd,0x72,0x9a,0x27,0x97,0x79, +0xeb,0xa7,0xb3,0x3e,0x1e,0x6b,0xee,0x43,0xee,0xa0,0x59,0xb6,0xd4,0x5c,0xf1,0x78,0xb0,0xbe,0x3f,0x5e, +0xdb,0xbf,0xd8,0xb8,0x6d,0xa8,0x23,0xf3,0x62,0x07,0xf4,0x64,0xb9,0xaf,0x16,0xde,0xc1,0xb9,0x53,0xaf, +0xef,0x61,0x5f,0xbb,0xa3,0xa9,0xd6,0xbd,0x1d,0x8f,0x9a,0x95,0xc6,0xb4,0x6d,0xf7,0x2f,0xd6,0x37,0xee, +0x6f,0xbe,0xee,0x9b,0x79,0xb3,0xf2,0xf5,0xf6,0x1c,0x8a,0x1e,0xf4,0xee,0x5a,0x8d,0x73,0x1b,0xaf,0x81, +0x73,0x9b,0x50,0xbe,0x5e,0xb7,0xd9,0x65,0x9e,0x83,0x6e,0xf7,0xf8,0xb3,0x59,0x1c,0xef,0xdf,0xef,0x35, +0x9b,0x93,0xd3,0x35,0xfd,0xf2,0x64,0x68,0xb8,0x83,0x6e,0xb3,0x79,0xfb,0xe3,0xa6,0xf5,0x75,0xb7,0x1f, +0xea,0xf3,0x18,0x95,0xf5,0x46,0x9f,0xae,0x96,0x6b,0xee,0xde,0x4f,0xa7,0xba,0xaa,0x77,0x06,0xe6,0xfa, +0xe7,0xf5,0xeb,0xd6,0x86,0xb3,0x51,0xd8,0x31,0x4e,0xb5,0x72,0xbb,0x67,0x9c,0x94,0xaf,0xb1,0xc4,0x7e, +0xb9,0x51,0xbf,0xfa,0x8c,0xd7,0xce,0x1d,0xd5,0xfb,0xd8,0xe9,0x67,0xec,0x17,0xe0,0xbe,0xb5,0x76,0x2a, +0x75,0xfd,0xf3,0xcf,0xee,0xfe,0xc1,0x74,0x3a,0xd8,0xb3,0xbc,0xd6,0xcd,0xd1,0xdd,0x69,0xa9,0xd9,0x6d, +0xac,0x77,0x8c,0x93,0xd6,0xc1,0x6e,0xb8,0xee,0x39,0x8e,0x13,0xfa,0x44,0x45,0xff,0xe0,0xc6,0xda,0x69, +0x8f,0xea,0xfb,0xea,0xfa,0xde,0x7e,0xdf,0x1e,0x34,0xf7,0x3b,0x7b,0x5a,0xc7,0x18,0x59,0x0d,0xad,0xbd, +0x3f,0x1a,0x44,0x70,0x04,0x5d,0xf6,0x71,0x9c,0x9f,0x09,0xde,0xf2,0x34,0xff,0xf3,0x8b,0xba,0xde,0xdb, +0xdd,0xf8,0x7c,0x65,0x5f,0x9f,0x6f,0x96,0xaf,0xd4,0xfa,0x66,0xc3,0x2d,0xcd,0xf4,0x93,0xdb,0xfa,0xdd, +0x4d,0xb8,0xcf,0x03,0x34,0x4e,0xf6,0x10,0x61,0xd0,0xe7,0x17,0xab,0x79,0x55,0x34,0x8e,0x7b,0xea,0x45, +0x7f,0xf0,0xf3,0x72,0x78,0x3c,0x2a,0x0c,0xed,0xba,0xbd,0x3f,0xeb,0x1d,0xdc,0x1e,0xdc,0xe1,0x55,0x83, +0xa7,0x53,0x74,0xf1,0xc6,0xdd,0xe2,0x56,0x94,0x9c,0x38,0x15,0x96,0xa0,0x46,0x91,0x14,0x95,0x20,0x84, +0x53,0xc9,0x46,0x6f,0x40,0xdb,0x08,0xb4,0x64,0x46,0xed,0x5b,0x7e,0x59,0xd4,0x00,0xd8,0x9d,0x76,0x8f, +0x52,0x54,0x65,0x58,0x14,0xca,0x2e,0xbb,0xb9,0x6a,0xa0,0x92,0x05,0x67,0xa3,0x63,0xf3,0xa0,0xbf,0x27, +0xed,0x11,0xf9,0x48,0x34,0x3b,0x11,0xd3,0x9b,0xe5,0xfb,0x8f,0xd8,0x28,0x82,0x0a,0x21,0xfd,0x98,0xd9, +0x36,0xe5,0x70,0x09,0xa6,0x62,0x47,0x76,0xc6,0xe7,0x9b,0x98,0x17,0x91,0xef,0x05,0x97,0x11,0x97,0xf0, +0xc5,0xde,0x9d,0x57,0x8c,0xf0,0x85,0xa8,0x6a,0xf8,0x1e,0xe4,0xb6,0x85,0x7c,0x02,0xac,0x5a,0x68,0x91, +0x3d,0x45,0xb4,0x3d,0xce,0x67,0x5d,0xb2,0x09,0xd2,0xef,0x05,0x87,0x65,0xbf,0x97,0x07,0x20,0x2f,0x51, +0x1e,0x98,0x72,0x2c,0xb7,0x8e,0xfc,0x3b,0xd2,0xf5,0x40,0x6d,0x32,0x19,0xf7,0x1e,0x19,0xf6,0x85,0xee, +0x8e,0x4d,0x2f,0x3c,0xce,0xe8,0xd8,0xc2,0x93,0x0d,0xea,0xab,0x69,0xf7,0x45,0x24,0x3b,0xea,0x8c,0x31, +0x20,0x05,0x56,0x5b,0x8e,0xdd,0x30,0x4c,0x07,0xc1,0xfe,0x00,0x1a,0x51,0x0c,0xad,0x96,0x10,0xd2,0x2f, +0xa1,0xd0,0x45,0x3c,0xb5,0x04,0xd7,0x89,0x13,0xac,0x08,0x7f,0xc9,0x2d,0x07,0x78,0xc9,0xec,0x1e,0xa8, +0x88,0x0f,0x67,0xd1,0xca,0xcc,0x2e,0x4a,0x28,0x2a,0xdd,0xe7,0x54,0x4b,0xe4,0x12,0xca,0x50,0xf7,0x06, +0x36,0x76,0x64,0xbb,0x5e,0xb8,0x51,0xa2,0x02,0x85,0x6c,0x93,0xf0,0x07,0x66,0x0c,0xc1,0xbb,0x41,0xe1, +0x63,0xbb,0xd5,0xbc,0xba,0x38,0xb8,0xbc,0x05,0xe8,0x0b,0xf0,0xa2,0xf8,0xb1,0x41,0x31,0x95,0xca,0xd8, +0x05,0x3c,0x28,0xde,0xc0,0x70,0x15,0x76,0x49,0xa5,0x32,0xb3,0xc7,0xca,0x40,0x9d,0xe8,0x8a,0x67,0xe3, +0x25,0xc9,0x56,0x9f,0x8e,0x2a,0x2a,0xfc,0xe6,0x37,0x45,0x0c,0x54,0x81,0xea,0xf4,0x01,0xa3,0xb9,0x94, +0x7f,0xa9,0x1a,0xa8,0xa8,0xff,0xca,0x2a,0x97,0xd8,0x92,0x5f,0x66,0x6a,0x98,0x00,0x19,0x95,0x09,0x2a, +0xfc,0xc1,0x2e,0x4a,0xfc,0x58,0x3f,0x53,0x10,0x43,0xca,0xc0,0xf6,0xdc,0x91,0xed,0x21,0x7e,0xe9,0x7d, +0x3a,0x54,0x0a,0xf0,0xa8,0xd0,0x56,0x1d,0xa8,0x4f,0xba,0x5f,0x46,0x49,0x4e,0xc1,0x36,0x62,0xc0,0x82, +0x8e,0xac,0x58,0xf6,0x34,0x45,0x26,0xa1,0x5c,0x15,0xbd,0x09,0x19,0x78,0x91,0x51,0x0d,0x47,0x61,0x5a, +0x8a,0xeb,0xb7,0x90,0x05,0x4c,0x14,0x61,0x32,0x01,0x5f,0x11,0x6c,0xf6,0x71,0xd2,0xc4,0x22,0x0e,0x7f, +0xcb,0xf4,0xf1,0xa2,0x68,0x5c,0x8c,0xc1,0xab,0x71,0xa6,0xa0,0x04,0x87,0x86,0x12,0x1f,0xeb,0x88,0x09, +0x1f,0x05,0x7f,0xe4,0xa8,0xf8,0xc7,0x3f,0x68,0x85,0xf2,0x7b,0x42,0x09,0x59,0x38,0xe9,0x89,0xd8,0x66, +0x4a,0xd0,0x8c,0x42,0xd6,0xb0,0x44,0x56,0x9e,0xda,0x21,0x37,0x47,0x2d,0x51,0x48,0x90,0x42,0xdc,0xb5, +0xc1,0x18,0xd4,0x3d,0x28,0xd4,0x03,0x0b,0x2b,0x42,0x68,0xd8,0x52,0x3e,0x04,0x56,0xcc,0x48,0x23,0x7d, +0x2a,0x68,0x7c,0x26,0x3e,0x5e,0x02,0x06,0x09,0x40,0x03,0x30,0x85,0xc7,0xc1,0x83,0xe9,0x84,0xa9,0xa5, +0x99,0x04,0xca,0x50,0xbb,0x5d,0xe0,0x26,0x8c,0x70,0x42,0x53,0xa4,0x24,0x65,0x82,0x48,0xa5,0x51,0x2f, +0x57,0x00,0x40,0x9b,0xe8,0x89,0xa9,0xcb,0xf8,0xc8,0x68,0x8a,0x28,0x0e,0xa6,0xd2,0x82,0x06,0x14,0x41, +0x10,0x48,0x27,0xb6,0xd2,0x03,0x28,0x07,0x8a,0xaa,0x58,0xfa,0x14,0x58,0xaa,0x33,0x9c,0xe2,0x3c,0x87, +0xa6,0x34,0x79,0x7a,0x59,0x4f,0x65,0xff,0xe8,0x38,0x1f,0x0f,0x3c,0x65,0x38,0x76,0x3d,0x46,0xb7,0xaa, +0xa7,0x80,0x82,0x0b,0xbf,0x04,0x1d,0xf4,0x30,0x54,0x16,0xef,0xfb,0x86,0xe5,0xa4,0x3b,0xae,0x44,0x44, +0x2c,0xcf,0x8e,0x4b,0x94,0xc3,0x34,0x27,0xf6,0xac,0x5a,0x33,0xc5,0xee,0x21,0x8c,0x2e,0x9a,0x76,0x7a, +0x17,0x8c,0x58,0xa9,0x85,0xaa,0xf2,0x67,0x3a,0xbb,0x5d,0xfd,0xdf,0xef,0x3e,0xfd,0xe7,0xfb,0x7f,0xfc, +0xf3,0xff,0xfa,0xa0,0x0e,0x47,0xdb,0xff,0xf1,0xc1,0xf4,0xb6,0x3f,0xf4,0xbd,0xed,0xff,0xf5,0x2b,0x99, +0x7a,0x7c,0xfa,0xf6,0x9d,0xd1,0xe3,0x1c,0x30,0x78,0x61,0x07,0xa6,0x8e,0xa5,0x93,0xf1,0x01,0x28,0x58, +0x56,0x2e,0xe2,0x1f,0x9e,0x0f,0x8a,0x00,0x5a,0xe4,0x12,0x0c,0x76,0x99,0x9e,0x69,0x82,0x63,0xa6,0x79, +0x05,0xa2,0xbd,0xa0,0x7d,0x9a,0xbf,0x92,0x6a,0x8b,0x8b,0xa8,0x36,0x96,0x2e,0x65,0xda,0x55,0x90,0xe5, +0xfb,0x05,0x99,0xf6,0x1c,0x94,0xe5,0xbf,0xe3,0x6d,0x11,0x01,0x10,0xfb,0x9a,0xf8,0x78,0x45,0x9f,0xff, +0xc8,0xb1,0xdf,0xd0,0x64,0xb0,0xcc,0x65,0xec,0xe5,0x90,0xfb,0x7e,0x9c,0x43,0x28,0xb2,0x6b,0x16,0x42, +0x1d,0xc3,0xe5,0x55,0xfa,0x8c,0x7a,0xc3,0x91,0x61,0xdd,0xf9,0x05,0xfc,0x00,0x6d,0xbc,0xe6,0x17,0x38, +0x35,0xb4,0xc7,0xff,0x51,0x83,0x46,0xb1,0x50,0x74,0xfd,0xf2,0x77,0x58,0x38,0xfc,0x52,0x78,0x08,0x13, +0x7c,0x5a,0x06,0x20,0x10,0xf0,0x29,0xf1,0x71,0xff,0xb4,0x7d,0x79,0x52,0x3f,0x6e,0xf1,0x2e,0x94,0x25, +0x95,0x15,0xd2,0x9e,0x44,0x13,0x74,0xb7,0x6d,0xe2,0x63,0xab,0x7d,0x36,0x76,0x2c,0x55,0xc9,0x67,0xe1, +0x8f,0x80,0x73,0x6c,0x46,0x5a,0xc0,0xa4,0x20,0x48,0x50,0x46,0xe4,0x3d,0x1e,0x20,0x21,0x3c,0x0c,0x1c, +0xbd,0x57,0x4b,0xbc,0x4f,0xcc,0xd5,0x43,0xb4,0xa0,0x41,0xc1,0x45,0x16,0xe6,0x05,0xf5,0xc6,0x6e,0xe2, +0x63,0xfb,0xb2,0x7e,0x79,0xd5,0x26,0x8c,0xe4,0x4c,0x63,0x41,0xd3,0xca,0xdc,0x29,0x95,0x97,0x75,0xd6, +0xd7,0x2d,0xdd,0x51,0xcd,0xc4,0xc7,0xbd,0xd6,0x49,0xeb,0xa2,0x7e,0xf4,0x6c,0x77,0xe4,0x47,0xe3,0xff, +0x64,0xb4,0xee,0xc3,0xcb,0xba,0xd3,0xec,0xa1,0xed,0x19,0x58,0x6b,0xe7,0xf4,0xf8,0xf4,0xf2,0xa0,0xf9, +0xf5,0x65,0x1d,0x0e,0xd4,0x97,0xf5,0x87,0xe5,0xf7,0xeb,0xed,0xe7,0xb1,0x18,0xea,0xc5,0xd0,0x3a,0x2f, +0xeb,0x86,0x2a,0x1c,0x9c,0xec,0x1e,0x5d,0x7d,0xd9,0x69,0xbc,0xac,0x2f,0xd2,0xbc,0x5f,0xd6,0x1b,0xaf, +0x72,0x74,0xb0,0xb7,0x7f,0xf9,0xc2,0x91,0x0d,0x7f,0x7a,0xde,0xcb,0x3a,0x63,0x35,0x8e,0xcf,0x2f,0x2f, +0x5f,0xd6,0x93,0xe5,0x8d,0x5e,0xd6,0x11,0x55,0x38,0xb9,0x3c,0x7b,0x59,0x37,0xa0,0xe5,0xbf,0xac,0x1b, +0xaa,0x70,0xb1,0xfb,0xb2,0x5e,0x40,0x6d,0x7f,0xe1,0x1a,0xe6,0x7a,0x3e,0xac,0xe2,0xe6,0x7e,0x6b,0xe7, +0xea,0xa8,0xf5,0xc2,0x0e,0x75,0xcb,0xb5,0x1d,0xf7,0x85,0x9d,0x8a,0x4a,0xed,0xd6,0x49,0xfb,0xf4,0xe2, +0x85,0xa4,0x81,0xdb,0xbf,0xb3,0x17,0xe2,0x92,0x55,0x69,0xdf,0x1c,0x5c,0xc2,0x28,0x5f,0xd8,0x1f,0x68, +0xb7,0x77,0x2f,0xeb,0x0e,0xb4,0x2a,0xab,0x0f,0x6a,0x87,0x0a,0xf5,0x2e,0xf7,0x0f,0x4e,0xf6,0xda,0x67, +0xad,0xfa,0xe7,0x67,0x7a,0x7d,0x59,0x17,0xe8,0xdf,0x4a,0x7c,0xbc,0x39,0xd8,0x3d,0xf8,0x8b,0xf9,0x2e, +0x69,0x0d,0xa0,0x15,0xef,0x1c,0x1f,0x9c,0xbc,0x90,0xe7,0x76,0xfa,0x2f,0xe4,0xb9,0x58,0x61,0xa7,0xd5, +0xb8,0xda,0x0b,0x3a,0xca,0x8d,0xcd,0x90,0x60,0x95,0x5d,0xc6,0x89,0xd5,0xb4,0x09,0x98,0x77,0x50,0x2b, +0x7d,0xa5,0x41,0x79,0xa6,0x92,0xef,0x14,0x46,0xad,0x8a,0x3f,0xbe,0xa0,0x32,0x3a,0x98,0xb1,0x26,0xfe, +0x2b,0x29,0x2a,0x51,0x25,0x89,0xf9,0x25,0x12,0x1f,0x3f,0x74,0xed,0xd1,0x6c,0x5b,0x29,0xe6,0xf1,0x80, +0x7c,0xbe,0x50,0x41,0x6d,0xf8,0x8b,0x0d,0x5a,0xeb,0xd9,0xff,0xf7,0x7f,0x3b,0xfa,0x03,0xfe,0xf4,0x51, +0x38,0xf0,0xbc,0x51,0x35,0x97,0xf3,0x00,0x71,0xba,0x33,0x54,0xad,0x6c,0x57,0xf5,0x50,0x45,0x43,0x77, +0x75,0x2d,0xf1,0x67,0xc7,0x54,0x51,0x4d,0x89,0x2b,0x45,0xf8,0x8c,0x36,0xe5,0x42,0xa9,0xbe,0xe1,0x0d, +0xc6,0x9d,0x2c,0x68,0x75,0xb9,0x7b,0xe8,0x15,0x74,0x56,0xfd,0x21,0xa7,0xbb,0x23,0xd4,0x23,0xe6,0x9b, +0x16,0x0a,0xc6,0x7f,0x2a,0x7b,0x86,0xb7,0x3f,0xee,0x88,0x66,0xf7,0xce,0x8e,0x26,0x25,0xc5,0x04,0x5b, +0xc0,0x02,0x85,0x17,0xfb,0x09,0x69,0x63,0xd1,0xb1,0x07,0x56,0xf4,0x02,0x2b,0x98,0x5b,0xe4,0xb2,0x8e, +0xb1,0xd0,0x2e,0xe6,0xba,0x07,0xb7,0x8a,0x9b,0x63,0x07,0x73,0xe4,0x28,0xcc,0x69,0x3e,0x66,0x1e,0x9e, +0x67,0x2c,0x45,0xb4,0xe4,0x43,0x76,0xbb,0x12,0x4e,0x44,0x39,0x67,0x4d,0x22,0x74,0xc4,0x51,0xdc,0x44, +0x54,0xbd,0x24,0x89,0x17,0xf3,0x1a,0xa9,0x29,0xfa,0x0e,0x6c,0x73,0x18,0xe1,0x7c,0xe1,0xa1,0xda,0xb7, +0x0c,0x6f,0xac,0xe9,0xe1,0x4f,0xf1,0xba,0x7f,0x51,0xa1,0xfd,0xab,0x79,0xeb,0x11,0x3e,0x81,0x34,0x54, +0xad,0x31,0x6e,0x5b,0x8c,0x1d,0xb4,0x34,0x62,0x9b,0xc2,0x8c,0x06,0x11,0x3d,0x95,0x5c,0x58,0x42,0xb7, +0x1c,0x4a,0x4d,0x24,0x02,0xed,0x37,0xb6,0x2d,0xec,0x72,0x87,0x6c,0xc2,0x57,0x76,0xc6,0x0c,0xca,0x55, +0xba,0x69,0x0e,0x8c,0x91,0x72,0xb0,0xf3,0xca,0x7e,0xba,0x50,0xdb,0xd0,0x56,0xe9,0xe7,0x06,0xf8,0xac, +0x72,0x5c,0x6f,0xbe,0x1a,0x7b,0xdd,0x55,0x7a,0x69,0xef,0x7c,0x56,0xc0,0x32,0x76,0x89,0x58,0x5f,0xd5, +0x91,0xab,0xdd,0xad,0x84,0x36,0xf4,0x19,0xfd,0x5e,0x4f,0x5d,0x6e,0xcd,0x3d,0xd7,0xd5,0xae,0xb0,0xf9, +0xb1,0xda,0x2b,0xfb,0x52,0x47,0xa3,0x3f,0x99,0x6d,0xf4,0x82,0xfe,0x7e,0x6f,0x78,0xd8,0x25,0x6f,0xe1, +0x45,0xbd,0x76,0xc6,0x86,0xa9,0x29,0xcc,0x3c,0x7d,0x75,0xc7,0xd4,0xc8,0x8b,0xba,0x45,0xff,0xf7,0x6b, +0x49,0xe6,0x4e,0xf7,0xba,0x83,0x3f,0xb1,0x85,0x84,0x82,0x6e,0xc9,0x5a,0x42,0xe9,0xcc,0x3c,0xc6,0x76, +0x9e,0x05,0xc0,0xd1,0x69,0xd3,0xfc,0xd5,0x4b,0xbd,0x07,0x0d,0xac,0xd0,0xf7,0x33,0xfc,0x0f,0x7b,0x59, +0xca,0x01,0x4f,0x98,0xe3,0xf9,0x95,0x40,0x72,0xb7,0xf5,0x2a,0x08,0x69,0xb4,0xdb,0xaf,0x66,0x47,0x1d, +0xd7,0x5d,0x8d,0x1b,0x35,0x99,0xcc,0x78,0x35,0xd7,0xa3,0xda,0xab,0x74,0x74,0x01,0xa3,0x79,0x65,0x2f, +0x0e,0x0c,0x66,0x95,0x2e,0x0e,0xce,0x96,0x77,0x20,0x54,0x95,0xe7,0xe5,0x85,0x31,0x92,0xfa,0x53,0x3f, +0x2a,0xc9,0xe5,0x75,0x3f,0x7a,0xba,0x09,0x13,0x2b,0xd5,0x48,0x3d,0x47,0xe8,0xa0,0x71,0x8c,0x5e,0x89, +0x0e,0xac,0xfa,0xf2,0xe5,0x75,0x64,0xab,0x9a,0x02,0x5a,0xab,0x03,0x3a,0xca,0x2b,0x3b,0xc6,0x5d,0x1e, +0xde,0x42,0xd0,0x23,0xfd,0xfd,0xcf,0xe7,0xfb,0xbf,0x6e,0xbe,0x56,0xe2,0x4d,0xba,0x20,0xf1,0x3e,0x29, +0xa1,0x0e,0x87,0xd7,0xcf,0xf5,0x18,0x6b,0xfd,0xa3,0x2d,0xaf,0xb4,0x49,0x01,0x5c,0x02,0x4c,0xbc,0xe3, +0x60,0xb1,0x44,0x86,0xef,0x6d,0xa1,0x54,0xbe,0x0c,0x2a,0x61,0xf8,0xbf,0x18,0x26,0xe6,0x62,0x58,0xcc, +0x65,0xbc,0xd1,0xef,0x40,0x24,0x74,0x5e,0xcc,0xf5,0xfe,0x76,0x30,0xd9,0xd3,0x55,0xe8,0xf4,0x6a,0xf4, +0x4c,0xaf,0xcb,0xfa,0x18,0x53,0xe5,0x95,0x96,0x03,0x7a,0xe0,0xc7,0xa3,0xdf,0x91,0xae,0x7d,0x1b,0xc8, +0x32,0x44,0x95,0x8a,0x8b,0xe6,0x9d,0xe6,0x2a,0xf0,0x2d,0x4e,0xe8,0xc8,0xce,0xe5,0x79,0x87,0x72,0x68, +0x03,0x10,0x0d,0xcc,0x95,0x37,0xff,0x14,0xdd,0xea,0x32,0xb7,0x36,0xbb,0x9a,0x4c,0x75,0x3c,0x6a,0x3f, +0x83,0xb6,0x70,0x8c,0x51,0x24,0x9b,0x43,0xbe,0x17,0x74,0x91,0x3d,0xe4,0x7b,0x47,0xb9,0x41,0xb4,0xc7, +0x2a,0x84,0x0d,0x22,0x65,0xa2,0x9a,0x63,0xdc,0x4b,0xfb,0x6b,0x76,0xd0,0xf6,0xb9,0x47,0x3b,0x76,0x17, +0xc2,0x77,0x77,0x2f,0xac,0xaf,0x0c,0xd5,0x7b,0x53,0xb7,0xfa,0xde,0xa0,0x96,0x28,0x15,0xc5,0x16,0x00, +0xee,0x8d,0x07,0x38,0xe5,0x76,0x76,0x68,0x57,0x6d,0xd9,0x26,0x44,0x71,0x95,0x8d,0x8a,0x17,0x6d,0xb2, +0x19,0x2e,0x0d,0x88,0x6d,0x91,0x1a,0x14,0x28,0xd9,0x9b,0x85,0x36,0x62,0x0d,0x0b,0xb7,0x37,0x1d,0x85, +0x2b,0x11,0x4a,0x92,0x5b,0xe6,0xb8,0xd1,0x24,0xb0,0x80,0x1b,0x4e,0x59,0xba,0x9c,0x82,0x6d,0x84,0x09, +0xd4,0x01,0x0e,0x66,0x0a,0x3f,0x65,0xc3,0xee,0x4c,0xc1,0xfd,0xb6,0x7a,0xbb,0x79,0x70,0xe0,0x6f,0x74, +0xfd,0x4b,0xfd,0x17,0xbc,0x75,0xec,0x71,0x7f,0xa0,0xfc,0xeb,0xe1,0x5f,0x4a,0x12,0x8a,0xaa,0x0a,0xee, +0x39,0x65,0xf0,0x3c,0x11,0x45,0xff,0x4f,0xb0,0x25,0x10,0xfa,0x4e,0x8a,0xed,0xca,0x6a,0x06,0x58,0xfc, +0x50,0x35,0x2f,0x55,0xdd,0xfa,0x57,0xda,0xdf,0x7a,0x1d,0xcc,0x46,0xb8,0x99,0x97,0xfc,0x57,0xe6,0x5f, +0x29,0xdc,0x0c,0xd6,0x01,0x0a,0x58,0x51,0x96,0x6e,0xc0,0x57,0x07,0x35,0x2d,0xc7,0xc3,0x8d,0x2c,0xdd, +0xc2,0xcd,0x61,0x6f,0x00,0x15,0x79,0x1d,0x02,0x7f,0x97,0xb6,0x88,0x01,0x05,0x3c,0xf6,0x8c,0x36,0x0a, +0xd5,0x3b,0x5d,0xd1,0x7b,0x3d,0xdc,0x37,0xc4,0xed,0x5e,0x77,0x60,0x8f,0x41,0x53,0xc6,0xa0,0x34,0x6c, +0x0c,0x7b,0x45,0x67,0x96,0xb4,0x03,0xd9,0x81,0x4e,0x4d,0xa3,0x7b,0xc7,0x76,0xb6,0x75,0x25,0xe1,0xfb, +0x61,0x12,0xdc,0xcf,0xf2,0x7b,0x9b,0x65,0x3b,0xf6,0x98,0xb2,0x1d,0x63,0x1f,0x30,0x59,0x60,0xc8,0xc7, +0x52,0x6a,0xc7,0xb3,0x76,0xc8,0x6f,0xb8,0x98,0x52,0x19,0x69,0xb2,0x9d,0xbc,0x79,0xe2,0x1c,0x1a,0xf0, +0x23,0x9f,0x00,0xac,0xe9,0x23,0x20,0xd0,0x7c,0x9e,0x48,0x9b,0x9e,0xf2,0x32,0xe9,0x6e,0xfc,0xad,0xa4, +0x4b,0x63,0x42,0xe2,0x1c,0x02,0xe5,0x1a,0x82,0x07,0xc2,0x44,0x69,0xba,0x87,0x73,0xa4,0x2a,0x9a,0x8c, +0x9f,0x64,0xcf,0xb1,0x31,0x50,0x18,0x0a,0x20,0xdc,0x43,0x97,0x11,0x2a,0xee,0x32,0xd3,0x36,0x28,0x9b, +0x6f,0x86,0x02,0x9a,0xad,0x1e,0xf0,0x6a,0xfe,0x28,0xf6,0x87,0x71,0x89,0xb0,0x94,0x83,0xb4,0xf7,0xec, +0xbb,0xd0,0xa0,0x7d,0x8a,0xfb,0x64,0xa4,0xa7,0xd2,0x29,0x15,0xc3,0xf3,0xa3,0x0e,0xa0,0x68,0x5f,0x8f, +0x02,0x94,0x55,0x0e,0xac,0xae,0x83,0xa9,0xfe,0x42,0x3d,0x1b,0x3d,0x3f,0x96,0x60,0xa0,0x4e,0x88,0x72, +0x1c,0x56,0x0b,0x47,0x26,0x0f,0x08,0xfb,0xe2,0x54,0xa4,0xb4,0x75,0x8f,0xb5,0x42,0x0c,0x11,0x8b,0xd2, +0x40,0x79,0xf8,0x7a,0xa4,0xdf,0x5b,0x68,0x7f,0x6a,0x5b,0xff,0xf2,0x10,0x36,0x95,0x37,0xed,0xea,0x9e, +0x3c,0x54,0x69,0x17,0x1c,0x1d,0x27,0xaa,0x09,0x2b,0x17,0x07,0x48,0x8c,0x20,0x0e,0x1d,0xc6,0x90,0xa2, +0xe2,0x41,0x25,0x9d,0xcd,0xa1,0x86,0x10,0x4d,0xbd,0x62,0x0d,0x11,0xd3,0x21,0xf6,0x90,0x19,0x95,0x49, +0x9d,0x4b,0x9b,0xd1,0x98,0x29,0x8b,0xc9,0x4b,0xc4,0x44,0x2f,0x66,0x55,0x82,0xb5,0x69,0xce,0x96,0x2d, +0xa3,0x88,0xba,0x60,0x92,0x1f,0xec,0x99,0x85,0x75,0xd4,0xda,0xa1,0xb1,0xfb,0xcb,0x89,0x05,0xae,0x0b, +0x85,0x54,0xd7,0x8e,0xe1,0x63,0x7e,0xd9,0x7a,0xf2,0xd7,0xc4,0x26,0xf4,0x66,0x8f,0x02,0x61,0x45,0x0c, +0xfe,0xc6,0xd8,0x35,0x14,0x97,0x2b,0x5f,0xec,0x6b,0xb4,0x54,0x05,0x7d,0xaf,0x48,0xe0,0xcb,0x8b,0xe5, +0xb9,0x76,0x09,0x93,0x04,0xd2,0x4e,0x5b,0x54,0x6c,0x1d,0x2d,0x6d,0x98,0x25,0x94,0x65,0xf1,0x25,0xb6, +0x44,0x7f,0x14,0x44,0xa0,0x20,0x84,0x8b,0x8a,0x96,0xfd,0xc6,0x56,0x28,0x0c,0x3c,0xa1,0x6e,0x4e,0xd5, +0x99,0xab,0x9c,0x9e,0x2c,0x2a,0xb3,0x19,0x94,0xd9,0xdd,0x0d,0x0a,0xe5,0x18,0xd6,0xff,0x76,0x71,0x28, +0xa8,0x4b,0xd3,0x7b,0x86,0xa5,0xbb,0x6c,0xa1,0xe9,0xb8,0x1a,0x91,0xf8,0x59,0x38,0x86,0x82,0xfe,0x7b, +0x05,0xe9,0x04,0xfe,0xa1,0x02,0x36,0x2c,0x7b,0x22,0xf4,0x1b,0x1e,0x45,0x92,0x90,0x66,0x39,0x11,0xb0, +0x03,0xca,0x03,0xa7,0x7a,0x4a,0x61,0xff,0x81,0x05,0x9c,0x78,0xce,0x8c,0xd3,0x32,0x17,0x0e,0xc0,0x19, +0x7a,0x8a,0x3b,0xa6,0xc0,0x96,0xde,0x18,0x57,0x1e,0xff,0x80,0xb7,0x4c,0x8a,0x66,0x1c,0x43,0xef,0xe1, +0x9a,0xa4,0xe6,0x74,0x30,0x8f,0x66,0x4a,0xd9,0x57,0x04,0x81,0x89,0x00,0x00,0xed,0xcb,0xba,0x1f,0xc7, +0xc2,0x4a,0xb0,0xef,0xfc,0x33,0x5f,0xdf,0x61,0x98,0x65,0x9a,0x4b,0xb0,0xda,0x38,0x3a,0x1c,0xa8,0xe0, +0x66,0xa7,0x27,0x04,0x37,0xb6,0x48,0xf1,0x29,0x0e,0xe3,0xc3,0x38,0xc1,0x4c,0xfe,0xc2,0x24,0x2a,0x36, +0x8a,0xd9,0x29,0x70,0x65,0x1e,0x89,0x05,0xff,0xeb,0x9b,0x76,0x07,0x14,0x38,0xd6,0xb6,0x62,0xd9,0xa0, +0x67,0x18,0x5d,0x52,0xe3,0xc2,0x20,0xc8,0xf4,0xcc,0x41,0x98,0x09,0xde,0x11,0xc3,0xb0,0x10,0x34,0x7e, +0xf4,0x01,0x84,0x39,0x62,0x52,0x55,0xf8,0x2d,0x49,0x58,0x2c,0x81,0x5a,0x0a,0x86,0x0b,0xff,0xe9,0xd9, +0x23,0xa3,0x8b,0x7a,0x4a,0x0e,0x16,0x70,0x2e,0x0f,0xd4,0x05,0xa2,0x8d,0xc9,0x7e,0x65,0xa4,0xce,0xd0, +0xcc,0xc4,0xc9,0xcd,0xa7,0x95,0x02,0x62,0xac,0xa8,0x24,0x51,0xe8,0xdb,0xfd,0x3e,0xf4,0x67,0x78,0xa9, +0x30,0x90,0x7c,0x01,0x2c,0x47,0x91,0xa2,0x12,0x83,0x44,0x07,0x3b,0x31,0x74,0x40,0x4c,0x80,0x8e,0xa1, +0xae,0x5a,0x14,0x80,0x84,0x5a,0x13,0x42,0x4f,0xc1,0xe5,0x40,0x6e,0x40,0x1b,0x16,0x6a,0xfc,0x71,0x13, +0x13,0xac,0x37,0xde,0xb3,0xa0,0x87,0x9e,0x8d,0x97,0xd3,0x10,0x20,0x12,0xd9,0x11,0xcb,0xa6,0xef,0xf0, +0x7b,0x06,0x35,0x5c,0xcf,0xc4,0x80,0xa2,0x1e,0x03,0x2f,0x0c,0x1a,0x9b,0x3c,0x5e,0xc6,0x1f,0x81,0x1f, +0x80,0x34,0x64,0x53,0x1c,0x8b,0x86,0x18,0xb8,0xd8,0xb2,0xb1,0x47,0x74,0x50,0x46,0x17,0xab,0x66,0x7e, +0x18,0xe9,0xd7,0x0d,0xc1,0x7a,0x7e,0x04,0x40,0x85,0x4b,0x86,0x90,0xf0,0xb9,0x52,0x82,0x6a,0x25,0x02, +0x0e,0xc4,0x86,0xc0,0x5a,0x05,0x16,0xd4,0xcb,0xe8,0xf7,0x23,0x13,0xe8,0x11,0x0f,0x4d,0xbc,0x40,0xd2, +0xa8,0xa6,0x7e,0xaf,0xae,0x10,0xa6,0x87,0xc5,0x48,0x69,0xec,0x8b,0x5d,0x1e,0x2e,0x74,0x16,0x3a,0x0b, +0x89,0xa5,0x31,0x0d,0x8f,0x29,0x6e,0xe2,0xbe,0x6b,0xdf,0x48,0xc4,0x36,0x5b,0x16,0x1d,0x5d,0x0b,0xd9, +0x16,0xa5,0xc4,0x62,0xd3,0x70,0xc1,0xb8,0xa2,0x96,0x9b,0xd8,0xb5,0x5e,0x60,0xb7,0x05,0x5b,0xd3,0xdc, +0x70,0x6b,0x13,0x5d,0x2b,0x39,0xce,0x27,0x5e,0xb2,0xa1,0xe5,0xc3,0xc6,0x8e,0x94,0xf9,0x5b,0xa7,0x61, +0x3f,0x09,0xda,0x9e,0x1c,0x28,0x6e,0x24,0x02,0x06,0xa9,0xc2,0x33,0x13,0x24,0xd7,0x7c,0x6e,0x96,0xf8, +0x28,0xdc,0x99,0xd5,0x5d,0xa2,0x19,0x50,0x63,0x6d,0x28,0xb3,0x2c,0x32,0xcd,0x9f,0x8d,0xd2,0x9c,0x6a, +0x00,0xd2,0xfc,0xc4,0xa6,0x4e,0xc0,0xa6,0xb1,0x40,0x79,0x63,0x48,0x8a,0x97,0x9a,0xa0,0x47,0x7c,0xd5, +0x1d,0x1b,0x79,0x15,0x86,0xe1,0x05,0xfc,0x83,0xb2,0x6a,0x2e,0xaa,0x05,0x12,0xf3,0x14,0x4a,0x23,0xc9, +0xff,0xc0,0x48,0xc5,0xa0,0xea,0x33,0x15,0x4b,0x48,0xaa,0xa6,0x04,0x9c,0xac,0x6d,0xac,0x20,0xaa,0x5f, +0xa6,0xda,0xa3,0xe4,0x55,0x06,0x9c,0x1d,0x68,0x06,0x58,0x5d,0xe4,0x1a,0xf2,0x07,0xc9,0x8d,0x2f,0xe0, +0xb5,0x3e,0x40,0x0f,0xba,0x36,0xbf,0x3a,0xfd,0x2d,0x4e,0x16,0x99,0x9d,0xf8,0x0d,0xc2,0x17,0x71,0x43, +0x0b,0x08,0x5f,0x04,0x07,0x71,0xb2,0x3f,0x42,0x16,0xee,0xbe,0x8e,0xdc,0x5f,0x6a,0x07,0x5e,0x81,0x0d, +0x41,0xd0,0xbd,0x01,0xeb,0x18,0xbb,0x7a,0x93,0x06,0x2a,0x59,0x81,0x28,0x1a,0x65,0xc2,0xad,0xac,0xa0, +0x75,0xbd,0xb5,0x66,0x76,0xe5,0x32,0x31,0x4b,0xd7,0xda,0xa0,0xcd,0xaf,0x53,0x28,0x2d,0xed,0x3c,0x2b, +0xaa,0xab,0x5c,0xec,0x35,0xfc,0xdf,0x5c,0xc8,0x92,0xd4,0xa0,0x88,0x5f,0xdd,0x12,0x37,0xdd,0x30,0x3c, +0x29,0xa0,0x09,0xdc,0x51,0xb6,0x56,0x66,0xb6,0xeb,0x1d,0xe5,0xea,0x20,0x0b,0x62,0x07,0x2a,0x90,0x93, +0x82,0xfc,0x1c,0x46,0x4f,0xb6,0x88,0x06,0xaa,0x1b,0x04,0xd1,0x96,0x80,0x26,0x87,0x43,0x76,0xd7,0x90, +0xe8,0x14,0xa5,0xca,0x05,0xe1,0x8a,0xaa,0x8d,0xb8,0x02,0xc2,0xbc,0x7d,0x7e,0x3f,0xbe,0x77,0xe0,0xf7, +0x4c,0x7f,0x44,0x07,0x0e,0x99,0x0d,0xe4,0x6d,0xe6,0x1d,0xda,0x5b,0x36,0xeb,0x85,0xc2,0xbf,0x69,0xda, +0x69,0x6a,0x43,0xd3,0xd6,0xe3,0x33,0xaa,0x29,0xc9,0x91,0x89,0x3a,0x02,0xb9,0x48,0x41,0x57,0x77,0x53, +0xe9,0x40,0xf5,0xc4,0x18,0x71,0x65,0xbf,0x7d,0xad,0x24,0x07,0x63,0x3d,0x03,0xcc,0x94,0x2f,0xc3,0x0c, +0x71,0xb4,0x94,0x42,0xc7,0x28,0x7e,0x7b,0x16,0xe8,0xb0,0xbb,0xa0,0x82,0xb7,0x99,0x88,0x1b,0x6c,0x72, +0xd9,0x54,0x6c,0xfd,0x9b,0x66,0x02,0x0c,0x70,0x50,0x97,0xa3,0xa4,0x8f,0xcb,0x2f,0x09,0x13,0xa4,0xa5, +0x38,0x32,0xe8,0x08,0xa5,0xd2,0x55,0xcd,0xee,0x18,0x4f,0x89,0x83,0x5a,0x0d,0xa3,0xe5,0x1a,0x20,0x4e, +0x26,0xf3,0xda,0x32,0x4d,0x72,0xe5,0x25,0xb7,0xbe,0x60,0xc9,0x91,0x9a,0xe3,0x9f,0x1d,0xe1,0x3e,0x09, +0xbc,0x3a,0x06,0xa7,0xdf,0x64,0x67,0x03,0x40,0xf1,0xe4,0x3b,0x8e,0x0a,0x48,0x60,0x76,0x5e,0x51,0x2c, +0x7e,0xae,0x66,0xe2,0x72,0xfd,0xfb,0x97,0x30,0x27,0x1e,0x22,0x6e,0x3c,0x54,0x0f,0xda,0x0b,0x06,0xa8, +0xbc,0x11,0x1f,0x6f,0x5e,0x2e,0x5d,0xcf,0xf9,0x7f,0x17,0x15,0x19,0xbd,0x05,0x54,0x34,0x55,0x9d,0x61, +0x88,0x86,0x84,0x3b,0x77,0x31,0xe1,0x21,0xdd,0xb1,0x2a,0x2f,0xa4,0xa7,0xf2,0x3c,0x3d,0x31,0x43,0x20, +0xb4,0xa0,0x01,0x81,0x1d,0x7b,0x42,0xf6,0x0c,0x49,0x12,0x6e,0x3d,0xbc,0x90,0xe8,0xca,0xff,0xa5,0x88, +0xae,0xaf,0xc2,0xb8,0x01,0x71,0x8e,0xa3,0x77,0xdf,0xc8,0xe0,0x80,0x51,0xef,0x61,0xab,0xff,0x25,0xe4, +0x45,0x74,0x7c,0xe4,0x37,0x0c,0xe9,0x07,0xf1,0x94,0x82,0xa3,0x60,0x6b,0x91,0xc9,0x99,0xb8,0xb9,0xff, +0x5d,0xdc,0x37,0xdb,0x6d,0x21,0x77,0xde,0x64,0x89,0xb7,0xdb,0x21,0x94,0xaf,0x82,0xce,0xbf,0x02,0xe5, +0xfe,0xb0,0x90,0x72,0x1d,0x1d,0x73,0xcd,0x30,0x4c,0x92,0x43,0x9e,0x3c,0x3a,0xb8,0xb6,0x2e,0x5a,0xed, +0x4b,0xa5,0x7e,0x76,0xc0,0x69,0x3e,0x38,0x97,0xc7,0xaa,0xe0,0x65,0x19,0xae,0x92,0x78,0xbf,0xbb,0x9b, +0xa7,0x9d,0x05,0x98,0x13,0xf4,0x29,0x05,0x02,0x3d,0x51,0x2c,0x97,0x31,0x4d,0x43,0xe2,0xb7,0xe6,0xa1, +0xc9,0xd8,0xad,0x9f,0x57,0xca,0x7d,0x9b,0xb9,0xb8,0x0c,0x1a,0x5c,0x60,0x73,0xff,0x7d,0x73,0x72,0x10, +0x68,0x48,0x4c,0xb8,0xb0,0x03,0x94,0xae,0x8f,0x70,0x77,0x68,0x23,0x5a,0x63,0x2c,0xa6,0x97,0x60,0x32, +0x18,0x32,0xdf,0xb4,0x7f,0x01,0x1e,0xe5,0xef,0xd1,0x0d,0x28,0xee,0x67,0x47,0x11,0x70,0x69,0x90,0x97, +0x0d,0x77,0xa0,0x0a,0x62,0xdf,0xa9,0x1c,0xd9,0x77,0x2a,0x2c,0x44,0xcd,0x5f,0xe9,0x2a,0x06,0xc0,0xc2, +0xbb,0x4f,0x44,0xeb,0x01,0x59,0x29,0xb4,0xe1,0x84,0xf6,0x35,0x97,0xef,0x36,0xac,0x01,0xa2,0xe5,0x67, +0x90,0xbe,0x1c,0x7b,0x0c,0xc5,0xb4,0xa4,0xe8,0xc2,0x7a,0x1f,0xe9,0xcf,0x02,0x9e,0x08,0x6f,0x0b,0x62, +0x00,0xc9,0x1e,0xb6,0xc0,0xed,0xbd,0xc8,0x84,0x04,0xd8,0x2d,0xcb,0x5a,0x84,0x1f,0x53,0xfe,0xa6,0xc8, +0x44,0x9f,0x09,0x47,0x53,0x47,0xf7,0xa6,0x98,0x57,0x29,0x30,0xfa,0x89,0x0e,0xdc,0x30,0xd2,0x5e,0x61, +0xbf,0xf3,0x03,0x00,0x8b,0xec,0x77,0x3a,0x18,0x70,0xd0,0xbe,0xbc,0xa8,0x5f,0x1e,0xe0,0x56,0x05,0xb7, +0xe3,0x59,0x18,0xb0,0x7c,0x10,0x15,0xa7,0x16,0x99,0x19,0xcc,0xf9,0xd8,0x31,0xbc,0x99,0xd8,0x2f,0xf8, +0xcb,0xc2,0x10,0xda,0x7e,0xfb,0x0b,0x96,0x57,0xa6,0x14,0xc6,0xfa,0xf2,0xd0,0xfe,0x48,0x9a,0x15,0xaa, +0x4a,0xd7,0xb7,0x25,0x3e,0x36,0xe8,0xcd,0x92,0x68,0xff,0xdf,0xe9,0x8e,0x67,0x6f,0x91,0xfb,0xbb,0x60, +0xaf,0xfe,0xa2,0x0e,0x79,0x9e,0x1b,0x85,0x51,0xf4,0xc7,0x5d,0xfe,0x13,0x3a,0xd5,0xe7,0x4e,0x34,0xbc, +0x8e,0xff,0xfd,0x45,0x47,0xac,0x97,0x04,0x87,0xfc,0xcf,0x99,0xeb,0xff,0x39,0x73,0xfd,0xdf,0xe5,0xcc, +0xf5,0x12,0x32,0x7e,0xc9,0x21,0xec,0x55,0x02,0xb5,0x2e,0x2f,0xcf,0x14,0xd4,0x20,0x63,0x61,0x07,0x12, +0x3d,0x83,0x6f,0xcf,0x86,0xbf,0x3c,0x1b,0x99,0x55,0xfa,0xfb,0x43,0xb3,0xf8,0x3e,0x1a,0x29,0xd4,0x22, +0x6f,0x45,0x78,0xc9,0x21,0xf1,0x80,0x4a,0x0d,0x2a,0xf4,0xcf,0x31,0xb0,0x53,0x97,0x76,0x8f,0x03,0xe1, +0xe9,0x81,0xe2,0xa7,0x54,0xf2,0x4a,0x12,0x4c,0x4e,0x4b,0x53,0x61,0x21,0xfb,0xc8,0x4a,0x05,0xfb,0xaa, +0x22,0x26,0x43,0xd5,0x68,0x8b,0x19,0x37,0xbc,0x8c,0xae,0xe1,0xb1,0x58,0x0e,0x8a,0xf9,0x10,0xcd,0x57, +0x15,0x1e,0xfd,0x35,0x9c,0x19,0xa3,0xea,0x70,0x86,0x0d,0xe5,0x7e,0x8b,0xfc,0xd8,0x3e,0x95,0x72,0xd3, +0x56,0xea,0x63,0x6f,0xf0,0x06,0xba,0xf8,0xd4,0xc5,0x86,0x12,0xbf,0xc7,0xda,0x39,0x54,0x84,0x2c,0x40, +0xef,0x5b,0x6c,0xca,0x8d,0x0c,0xb1,0x25,0xf7,0x7b,0xa0,0x5d,0xe8,0x78,0xff,0x37,0xaa,0x9f,0x6f,0x06, +0x18,0x36,0x79,0xc9,0x63,0x58,0xff,0x66,0x3d,0xba,0x31,0x13,0x29,0x5d,0xd2,0x8a,0x6b,0x53,0xc4,0xa0, +0x38,0x36,0x46,0x3b,0xb0,0x1d,0x1d,0xfd,0x2c,0x23,0xb0,0x10,0x1d,0x1b,0xc5,0x0e,0x1a,0x89,0x40,0xf2, +0xec,0x56,0x2e,0x2e,0x8f,0x26,0xb6,0x01,0xfa,0xd8,0x08,0xd4,0x31,0x7b,0xec,0x0a,0xf7,0x22,0xae,0x03, +0x22,0x70,0xbe,0xcf,0x8e,0x21,0x58,0x0e,0x8c,0x33,0x43,0xa8,0x63,0x85,0x40,0x0a,0xd8,0x5e,0xa8,0xf1, +0x94,0x70,0xd1,0xe0,0x9a,0xf2,0xc6,0x0e,0x46,0x2d,0x86,0x82,0x8e,0x7e,0x8f,0xd7,0x0a,0x7a,0x52,0x3e, +0xeb,0xf1,0xc1,0x7a,0x30,0x19,0xf0,0x29,0xc4,0xab,0x10,0x57,0x12,0xfa,0x43,0xdc,0x2a,0x62,0x04,0xcd, +0x69,0x4e,0xeb,0x2f,0xd1,0x9c,0x58,0x1a,0x39,0x59,0x41,0x83,0x85,0x64,0x3f,0xa3,0x9d,0xbd,0x01,0x77, +0xc3,0x4e,0xe7,0x58,0x11,0xca,0x11,0x16,0x9e,0xc1,0x62,0x57,0x08,0x73,0x9c,0x0b,0x09,0x1d,0x02,0x10, +0x99,0x56,0x78,0x48,0x27,0x9f,0x61,0xe0,0x91,0x53,0x07,0x1d,0x78,0x82,0x0a,0x70,0xd3,0x12,0x11,0xde, +0x55,0x4d,0xd3,0x65,0x9a,0x82,0x88,0x47,0x95,0x73,0xf4,0xb0,0xb1,0x07,0x02,0x77,0x04,0xf2,0x7e,0xa8, +0x63,0xf8,0x19,0xc1,0x80,0x45,0x59,0x6c,0x1d,0xf9,0x84,0xb2,0xca,0xa5,0xad,0xdc,0x59,0xf6,0x14,0xf4, +0x17,0x10,0x9d,0xd0,0x3e,0x23,0x56,0x61,0x74,0x6b,0x36,0x45,0xb0,0x42,0xd7,0x52,0xa0,0x5b,0x0e,0xfa, +0x70,0x57,0x92,0xd9,0xd1,0x83,0xdb,0x74,0xce,0x63,0x65,0x9e,0x75,0xd9,0x3a,0x3a,0x69,0x5d,0xbe,0x01, +0x63,0x60,0xfd,0xb6,0x2f,0xeb,0xff,0x0e,0xf3,0x1a,0x97,0xde,0xe9,0x09,0xc5,0x12,0x06,0x41,0x3f,0x0c, +0x22,0x5f,0x28,0xf9,0x3a,0xa4,0x81,0x5e,0x5c,0x3f,0x48,0x4a,0x7c,0x1e,0x20,0x3b,0x01,0x0b,0xd7,0x43, +0x93,0x1b,0x63,0x3d,0x09,0x31,0xcc,0x9f,0x47,0xc1,0x1e,0x62,0xba,0xe4,0x68,0xa8,0x95,0x67,0xc5,0xb2, +0x7b,0x63,0xd7,0x5d,0xc1,0x48,0x80,0x35,0x34,0x04,0xb3,0xb1,0x0b,0xd4,0x3b,0xb4,0x3d,0x5d,0x64,0x80, +0x52,0x92,0x27,0xf6,0xee,0x55,0xbb,0x9d,0x7a,0x83,0x99,0x62,0xb0,0xac,0x22,0x5e,0x5e,0x39,0x08,0x06, +0x2a,0xf0,0x40,0x67,0x22,0x6d,0x37,0xca,0x8c,0x8b,0xb5,0xd4,0xa6,0x02,0xcf,0x2a,0x89,0x73,0xcc,0xab, +0xfc,0x86,0x26,0x8c,0x88,0x68,0x07,0x65,0x06,0x33,0xcd,0x89,0x9d,0xa7,0xd0,0x10,0x48,0x99,0x52,0x17, +0xce,0x8c,0x8b,0x67,0xa5,0xf8,0xd1,0xf2,0x8e,0xe1,0x75,0xc6,0xdd,0x3b,0xdd,0xcb,0xda,0x4e,0x5f,0x3a, +0x5d,0xce,0x06,0x9c,0xfa,0x4d,0x9f,0x30,0x4b,0x8b,0x17,0xc1,0x68,0x88,0x85,0x17,0x43,0xcc,0x9f,0x1f, +0x3a,0x04,0x82,0x67,0x87,0x0f,0x64,0x7c,0x82,0x74,0xd3,0xd0,0xa3,0x8d,0xca,0x2b,0x7b,0x7a,0x46,0x24, +0x54,0x9e,0x15,0x09,0xe1,0xe4,0xa0,0x21,0x5f,0x01,0xbd,0x79,0xd6,0x74,0x7f,0x4d,0x6f,0x72,0x37,0x3e, +0x82,0xfe,0x1a,0x21,0x14,0xda,0x1b,0x62,0xa7,0x6e,0xa2,0xc7,0x3a,0xc5,0xb1,0x1e,0x76,0xe8,0x0d,0x94, +0x0d,0xd5,0x30,0x89,0x1f,0x21,0x09,0x81,0x15,0x2a,0xa8,0x46,0x28,0x1c,0x8e,0x42,0x79,0x4a,0x91,0xcd, +0x98,0x98,0x77,0xc0,0x61,0x3a,0x38,0xe9,0x10,0xe8,0x25,0xa4,0x7d,0x20,0xcd,0x66,0x91,0x8a,0x2f,0x4a, +0x64,0x90,0x9b,0x1a,0x77,0x46,0xee,0x72,0x6a,0xb7,0x3d,0x7d,0xc4,0x52,0x48,0xb9,0xf3,0xc9,0x0d,0x84, +0xb8,0xf1,0xa6,0x76,0x06,0x23,0xf6,0xfd,0xf3,0x46,0xfc,0x3d,0x1e,0x14,0xcc,0xbe,0x0d,0x1a,0xa1,0x8c, +0xc8,0xe7,0x48,0x8e,0xb6,0x68,0x92,0x47,0x6c,0x43,0x3c,0x8b,0xe6,0x64,0x9e,0xc1,0xcb,0x0b,0x2a,0x46, +0xaa,0x0e,0x71,0x85,0x8d,0xdf,0x89,0xd7,0x61,0x99,0x45,0x16,0xb9,0xfb,0x58,0xc6,0x11,0xee,0xe4,0xc3, +0xd8,0x74,0x3c,0x1e,0x22,0xa2,0x75,0x90,0x13,0xa0,0x14,0x29,0x4b,0x86,0x14,0xc5,0x24,0x8a,0xf4,0x8f, +0x74,0xa4,0x24,0x14,0x07,0xef,0x39,0x33,0xd9,0xc9,0x81,0xa7,0x5d,0xe8,0x18,0x00,0x30,0x1f,0xd7,0xe8, +0x5b,0x14,0xf8,0xea,0xd0,0x61,0xa0,0x95,0x13,0xfe,0xf1,0x20,0xb6,0x67,0x82,0xda,0x56,0xf0,0x1f,0xb2, +0x93,0x2f,0x0c,0xf2,0xb7,0xb0,0xaf,0x00,0xb1,0xd8,0x66,0xf4,0xd4,0xd2,0xdf,0xad,0x22,0x88,0x2c,0x1e, +0x2c,0x3a,0x14,0x07,0x89,0x2b,0x72,0x62,0xb8,0x06,0xd9,0x93,0x38,0x5f,0x78,0x96,0x99,0x79,0x75,0x22, +0xf3,0x03,0x8f,0x7e,0x2a,0x4f,0x16,0xe7,0x8d,0xc1,0x64,0x18,0x7f,0x2a,0xcf,0x9c,0x58,0x4a,0x91,0x19, +0x94,0x32,0x44,0x82,0x6e,0x6a,0xe1,0x3e,0x15,0x3b,0x01,0x67,0xa2,0x4a,0xaa,0xb8,0x03,0x54,0x05,0x69, +0x9b,0x17,0xc5,0x10,0xc2,0x90,0x55,0x28,0x64,0x56,0x5c,0x27,0x90,0x56,0x42,0xb0,0xcf,0xc3,0x86,0x95, +0x7d,0xf8,0xc4,0x9e,0x31,0x36,0xc6,0x40,0xf3,0xf0,0x3c,0x13,0x76,0x82,0x39,0xd0,0x04,0xe4,0x59,0x85, +0x5f,0x59,0xcc,0x58,0x0d,0x8f,0xde,0x93,0xce,0x93,0x88,0xd1,0xf0,0x7e,0xc4,0x01,0x0a,0x05,0x33,0x6f, +0x42,0x2d,0xee,0xd5,0xa3,0x0b,0xe9,0x24,0x37,0x19,0xa0,0x94,0xa9,0x50,0x29,0xee,0x9b,0x53,0xfd,0x86, +0xd8,0x65,0xcf,0x0a,0x3b,0x30,0x1e,0x51,0x6b,0x57,0x99,0xe2,0xe5,0xc2,0xc0,0xcf,0x7c,0x1d,0x4d,0x9e, +0xc7,0xe8,0xd9,0x9e,0x06,0x32,0x61,0x49,0x67,0x8c,0x30,0x78,0x6e,0xe9,0xe7,0x0c,0xef,0x70,0x9e,0x3a, +0x24,0x3a,0x91,0xf2,0x9e,0x31,0x96,0x20,0xad,0xab,0x9f,0x7b,0x20,0x78,0x13,0x39,0xfe,0xc9,0x57,0xeb, +0x49,0xb0,0xee,0xa4,0xe5,0x8b,0x8d,0x89,0xf9,0x8d,0xa2,0x23,0x34,0xd8,0x85,0xa6,0x5a,0x90,0x90,0x1d, +0xdd,0xd0,0x9a,0xa0,0x96,0x67,0x53,0x0a,0x2e,0xe3,0x98,0x41,0x0e,0xad,0x85,0xd1,0xbd,0x7e,0x6e,0x2d, +0xce,0x39,0x49,0x4d,0xf7,0xa3,0x32,0x41,0x5f,0x17,0x07,0x00,0x30,0xe4,0x5e,0x63,0xb6,0x33,0xa8,0xe6, +0xd2,0xc9,0xde,0x17,0xe5,0x3b,0x65,0x48,0xe7,0x19,0x7c,0x5f,0x8d,0xa8,0x48,0xde,0xf6,0xf8,0x34,0x5c, +0x88,0x44,0x1e,0x08,0x2b,0x0a,0xce,0x67,0x4b,0x5a,0xb9,0xcb,0x70,0x16,0xf9,0xf8,0x0c,0x74,0xd8,0xa3, +0x88,0x64,0x99,0xeb,0xf2,0x35,0xf3,0xc7,0x8f,0x8c,0x2f,0x98,0x3b,0x96,0x51,0x4e,0xe4,0x17,0xf2,0x25, +0x1d,0x50,0xbc,0x58,0xcf,0xb4,0xa9,0x08,0x9a,0xde,0x9d,0xe4,0x5a,0x9e,0x3b,0xfd,0x89,0x13,0x1c,0x77, +0x1e,0x43,0x4a,0xd1,0x2b,0xd0,0xc8,0x82,0x5c,0x26,0x86,0x8a,0x9d,0xb0,0x63,0x1d,0xec,0x60,0xc6,0x5f, +0x96,0xf3,0x96,0x5b,0xc0,0x6c,0xa8,0xbf,0x2d,0xe8,0x10,0x9f,0x31,0x51,0xf4,0xa5,0xfc,0x73,0x7c,0xe4, +0x19,0x28,0x09,0x15,0x0d,0x8e,0xe7,0x85,0x8a,0x7f,0xc8,0x43,0x2d,0x9d,0xf9,0xe7,0x16,0x56,0xbc,0x21, +0x55,0x2c,0x24,0x94,0x91,0xa9,0x76,0xf5,0x81,0x6d,0xc2,0xcc,0xd7,0x12,0x07,0x67,0xc8,0xb6,0x25,0x53, +0x88,0x26,0x93,0x4d,0xf2,0xab,0xfd,0xed,0x34,0x80,0xb3,0x79,0x7f,0xfb,0x0a,0xe0,0x33,0x4f,0xfc,0x02, +0xe0,0xc1,0xbe,0x11,0xc1,0xed,0x95,0xca,0x82,0xb8,0x89,0x55,0xc1,0xbb,0x72,0x5f,0x83,0x5d,0xac,0xb5, +0x10,0xbc,0x52,0x04,0xb7,0x47,0x3a,0xfa,0xaa,0x48,0xed,0x46,0x39,0x6b,0xd9,0x94,0x83,0xfa,0x6d,0xb7, +0x36,0x18,0xaa,0xe3,0xb7,0x66,0x56,0x41,0xb7,0x1a,0x4e,0x40,0x1b,0x9b,0x11,0x77,0xfd,0xd9,0x71,0x8d, +0x68,0xe7,0xe7,0xcd,0xc7,0xd5,0x34,0x0d,0x14,0x0b,0xa8,0x3e,0xbc,0x74,0x60,0xac,0xea,0xc1,0xce,0xc2, +0xc9,0x5a,0xee,0x51,0xf8,0x0b,0x02,0x6e,0x30,0xd7,0xbf,0xa2,0x0f,0x47,0xde,0x4c,0x04,0xaa,0xb3,0x6d, +0x4b,0x62,0x94,0x2c,0xdf,0x81,0xa7,0xa3,0x5b,0x50,0x0c,0x3a,0x2c,0x23,0x81,0x72,0x70,0xa3,0x91,0x1f, +0x03,0xe6,0x3e,0x0b,0xcc,0xef,0xf5,0x7b,0x0e,0x06,0xc2,0xf3,0xb9,0xdd,0x8e,0x1e,0x58,0x59,0x01,0xc5, +0x50,0x2b,0x84,0x51,0xb4,0xc6,0xe6,0xce,0xab,0xe4,0xab,0x4a,0xdd,0xa3,0x33,0x57,0x30,0x90,0xee,0xc2, +0xd3,0x23,0x60,0x1f,0x14,0xa8,0x24,0xdb,0x10,0x5d,0x56,0x14,0xa6,0xa6,0x58,0x55,0x5a,0xf7,0x6a,0x97, +0x9d,0xf4,0x92,0x4b,0xfa,0xe7,0x4c,0x7e,0x03,0x19,0x17,0x3a,0x3a,0x7f,0xdf,0x48,0x3c,0xb0,0xc6,0x42, +0x68,0xda,0x7c,0x0b,0xe9,0xf0,0x59,0x07,0xc3,0xbd,0x6e,0xd2,0x79,0x9c,0xd5,0x96,0x46,0x5c,0x04,0x15, +0x42,0x88,0x2d,0x45,0x03,0xa8,0x4a,0x1b,0xe1,0x00,0xaa,0xe2,0x82,0x13,0x1d,0x73,0x27,0xa6,0xa0,0x3d, +0xd7,0x35,0x57,0x0b,0x75,0xa4,0xf8,0x18,0xdf,0x2d,0x8b,0x13,0x9c,0x6c,0xb7,0x8f,0xde,0xc2,0xdb,0xc9, +0x19,0x35,0xb4,0x16,0x1a,0xc4,0xd6,0x52,0xc4,0xbf,0x76,0x28,0xd0,0x8b,0xb2,0x0b,0xb6,0x83,0xee,0x8c, +0x1c,0xb2,0x8c,0x9e,0x9d,0x8e,0x52,0x78,0x19,0xed,0x9e,0x85,0x79,0x94,0x94,0x15,0xa4,0xbc,0x35,0xa7, +0x57,0xbc,0xfd,0xee,0x4a,0x2f,0x00,0xde,0xdf,0x42,0xc6,0x41,0x75,0x75,0x87,0x1f,0xc1,0xf5,0x8f,0x67, +0x32,0xdf,0xa8,0x7f,0x5c,0x1f,0x2d,0x27,0xdc,0x53,0x31,0x3c,0x7e,0x3d,0xc3,0x9c,0xb7,0x6a,0x3a,0x9d, +0x66,0xfb,0x4e,0x97,0xdc,0x55,0x52,0x3f,0x6e,0x76,0xe0,0x0d,0xe3,0x33,0x7a,0x3e,0x57,0x4b,0xa4,0xe2, +0xb4,0x1d,0xde,0xa7,0x3d,0xd2,0x2d,0x98,0x28,0x16,0x4d,0xa7,0x82,0xc5,0x6b,0x8d,0xef,0x15,0x20,0x06, +0xcc,0xae,0x01,0x68,0xc5,0xdb,0x33,0x28,0x53,0xe7,0xc8,0xd1,0x3f,0xfe,0xc3,0x2f,0xed,0xfe,0xc9,0xd9, +0x6c,0x46,0x58,0xd5,0x22,0x5b,0x09,0x86,0x69,0x54,0xf1,0x07,0xee,0x5c,0xe3,0x0f,0xfa,0xa2,0xe4,0x34, +0x7d,0x92,0xb3,0xc6,0xc0,0xaa,0x8b,0x74,0x46,0xd8,0xff,0xf9,0xcb,0x6f,0xf3,0xbe,0x9c,0xdf,0x52,0x32, +0x32,0x3a,0x33,0x96,0x8d,0x47,0x1b,0x32,0xa0,0x23,0x53,0x05,0xd7,0xd3,0x90,0xb3,0x20,0x28,0xbf,0xcf, +0x02,0x2e,0x30,0x2b,0xc2,0x25,0x1e,0x5a,0x7e,0x39,0xcd,0x51,0xb5,0x45,0xa2,0xb1,0xb4,0x3c,0xc5,0xcc, +0x6b,0xe9,0xcc,0xa1,0x2c,0x0e,0xd8,0x71,0x90,0xa8,0x81,0x79,0xc8,0x98,0xb7,0xec,0x51,0xe4,0x8a,0x79, +0x22,0x1b,0xe2,0x71,0xa8,0x76,0x9f,0x64,0xbd,0xc3,0x95,0xa3,0x81,0xf1,0xb5,0x46,0x53,0x2c,0xb9,0x68, +0x45,0x4e,0x19,0xac,0x7e,0x5c,0x6f,0x0a,0xad,0x96,0xe8,0x35,0xe3,0x5b,0x31,0x38,0x9d,0x08,0x0b,0x4d, +0x23,0x19,0x77,0xb9,0xf7,0x39,0x0a,0xf9,0x12,0x26,0x4d,0x1b,0x0f,0x93,0xaa,0x4a,0x9e,0x34,0x63,0xa5, +0x80,0x41,0xc7,0xc1,0x11,0x70,0xf2,0xbe,0xe0,0x90,0x68,0x24,0x78,0xd0,0x9c,0x59,0x33,0x06,0x4a,0x2d, +0x3a,0x6c,0xd9,0xeb,0xb1,0x1c,0x1a,0xb8,0x3c,0x28,0xb8,0xc9,0x65,0xed,0x15,0x15,0xf9,0xc0,0xb8,0xeb, +0x5b,0xbd,0x74,0x3a,0x3d,0x0b,0x72,0x87,0x46,0xa5,0xbc,0x0f,0x76,0x14,0x79,0xd3,0xa0,0x0a,0x24,0x29, +0x89,0x0c,0x25,0xb9,0xa0,0x34,0x25,0x29,0xf2,0x26,0xfb,0x89,0x05,0xc8,0x3d,0x4d,0xc1,0xea,0xd2,0x79, +0x4d,0x29,0xc3,0x48,0x9e,0x70,0x10,0xf2,0x5f,0xc4,0x9a,0x9c,0x8b,0xb0,0xd4,0xef,0x44,0x31,0xe4,0x49, +0xa7,0xe5,0xa4,0xbb,0x59,0x08,0x2b,0x69,0x66,0x44,0xe0,0xf8,0x45,0x3e,0x1d,0xc2,0x80,0xa5,0x24,0xde, +0x5f,0x5c,0xec,0xed,0x35,0x1a,0x5c,0x8f,0x47,0x74,0x25,0x2e,0x2e,0x2e,0xd2,0x7b,0x7b,0x7b,0xe9,0x06, +0xbe,0x4e,0xe6,0x33,0xc5,0x72,0x59,0xd1,0xd5,0xee,0x80,0x45,0x6f,0xc9,0x99,0xac,0x5e,0x03,0xfa,0xc0, +0x9d,0x3c,0x0f,0xfa,0x00,0x40,0x81,0x9e,0x41,0xec,0xa5,0xd2,0x4a,0x70,0x10,0x0c,0xdf,0x15,0xf2,0x79, +0x16,0xac,0xc5,0x00,0x16,0x6f,0xd8,0xee,0x71,0x1a,0x5a,0xc1,0xb3,0x04,0xae,0x8e,0xdb,0xc1,0x9e,0xae, +0xbd,0x09,0xc8,0xc1,0x69,0xb5,0x78,0xc8,0xe9,0x3b,0x7e,0xe6,0xd8,0x7a,0x1b,0x44,0x71,0x4f,0xc3,0xfc, +0x5a,0xf0,0xa4,0xcd,0x6d,0xda,0x15,0x13,0x0e,0xc1,0x20,0x72,0x1c,0x3d,0x14,0x02,0x96,0x38,0x3a,0x16, +0x65,0x62,0x08,0x99,0x70,0xcb,0xbc,0xe9,0xeb,0xe2,0x20,0xc6,0x4d,0x93,0xc7,0xf4,0xbe,0xcd,0xc8,0x86, +0x86,0xa3,0x6b,0xf1,0xa3,0x92,0xce,0x54,0xf1,0xe1,0x50,0xc4,0xb6,0x13,0x9e,0xc9,0x05,0xed,0x8a,0xcc, +0x2b,0xa2,0xd1,0xa8,0xcb,0x9f,0x9f,0x73,0x40,0x0e,0x12,0x66,0x1a,0x2c,0x60,0xa1,0xa7,0x4f,0x51,0xed, +0x1a,0xd3,0xd6,0xd0,0xd5,0xc8,0xe6,0x2e,0x10,0xcd,0x70,0x65,0x07,0xac,0x7f,0x7e,0x08,0x83,0xf2,0xd9, +0xd6,0x76,0x9e,0x33,0xb4,0x53,0x5a,0x5a,0x3c,0x50,0xc5,0x3f,0x21,0x91,0xd4,0xf4,0x11,0x4f,0x74,0xc1, +0x2d,0x07,0x4a,0xb6,0x9a,0x42,0x17,0x6f,0x55,0x0a,0x7b,0x64,0xd6,0x47,0x7c,0x90,0xa1,0x9f,0x59,0xd6, +0xf7,0x63,0xfb,0x2e,0x5d,0x3f,0xe5,0xd9,0xdc,0x27,0xcc,0x73,0x39,0xf7,0x92,0x32,0x0a,0xfb,0x6f,0x65, +0x3f,0x39,0x90,0x46,0x52,0x94,0x62,0x59,0x38,0xf9,0x8f,0x54,0x50,0x7b,0xcc,0xb3,0xee,0xf9,0xce,0x66, +0x98,0x1d,0x9e,0xc3,0x44,0x2a,0xd5,0x0b,0x32,0x57,0xc6,0x0d,0x66,0x44,0xd9,0x9b,0xdc,0x31,0x26,0x02, +0x7a,0xa3,0x88,0x48,0x54,0x5f,0x0f,0xdb,0xa7,0x27,0x42,0x28,0x3c,0xab,0xb3,0x96,0x56,0xd5,0x59,0x0f, +0x5d,0x3b,0x64,0x2d,0x94,0x16,0x1a,0xa2,0x85,0xd7,0x49,0x64,0x0c,0x77,0xe1,0x5e,0x36,0xe0,0x1f,0xfa, +0x7d,0x57,0x1f,0x85,0x12,0x3b,0x31,0xa2,0x4e,0xf9,0x34,0x67,0x58,0x5d,0x73,0xac,0xb1,0x18,0x08,0x35, +0x34,0x68,0x90,0x6d,0x80,0xc9,0x60,0x91,0xe3,0x54,0x41,0xed,0xe1,0x88,0xb0,0x1f,0x12,0xc6,0x2e,0x8a, +0xb9,0xb1,0xc5,0xb7,0x26,0xe2,0x57,0x13,0x26,0x05,0x0c,0x26,0x90,0x16,0x0a,0xd1,0xf9,0xb1,0x00,0x56, +0x40,0xf4,0x73,0xac,0x8f,0x79,0x90,0x17,0xb5,0xcb,0x92,0x40,0x15,0x30,0x65,0x17,0x46,0x88,0x49,0x5b, +0x72,0xfe,0x38,0xbb,0x22,0x19,0xc0,0x50,0x07,0x8d,0x13,0xc7,0x22,0x6f,0x6c,0xf0,0xf1,0x50,0x6f,0xed, +0x71,0xc7,0xed,0x3a,0x06,0x99,0x93,0xae,0xc8,0x2b,0xc2,0x3b,0xd6,0x50,0xb6,0xa2,0xc0,0x67,0xd5,0x08, +0xc4,0xdf,0x3f,0x76,0xc0,0xf2,0x53,0x2e,0xf0,0xc9,0xd2,0xed,0x1b,0x73,0x2e,0x59,0x92,0xae,0x98,0x9f, +0x33,0xc9,0x77,0x0f,0x14,0x3a,0x6c,0x72,0xe6,0xd8,0xe8,0x7f,0x31,0x53,0x5c,0x4f,0xe7,0xa1,0xcb,0x98, +0x74,0x2f,0x92,0x16,0x11,0x06,0x71,0x87,0x06,0xa4,0x1c,0x24,0x43,0x51,0x6f,0x8c,0x11,0x33,0x55,0x9f, +0x52,0x01,0x21,0x47,0xa6,0x52,0x94,0x85,0x86,0x72,0xf1,0xfc,0x45,0xae,0x59,0x7e,0x90,0x42,0x24,0xf9, +0xbc,0x34,0xe6,0xf2,0x2a,0x3e,0xa3,0xd7,0x62,0x26,0xcf,0xe7,0xc3,0x1d,0x5e,0xb7,0xe0,0x29,0x19,0x6a, +0x5c,0x6c,0xcb,0x73,0x30,0x79,0xa3,0xe5,0xfe,0xd8,0xf5,0x05,0x1b,0xa3,0xab,0x1c,0xae,0xc2,0x09,0xfb, +0x0a,0x34,0xf9,0x42,0xd7,0x0d,0xc0,0x74,0xda,0xeb,0x51,0x76,0x23,0x09,0x0e,0xe2,0x33,0xbf,0xe7,0x3d, +0xe1,0xce,0xf5,0x9d,0xf6,0x5b,0xf8,0xd6,0x01,0x4a,0x68,0xe8,0x37,0x5d,0x25,0xd0,0x02,0xa8,0x23,0x7d, +0xf9,0x0c,0xeb,0xca,0x38,0x62,0xf5,0xe2,0x5c,0x5a,0xad,0xb1,0x03,0x26,0xdf,0x12,0x4f,0xd6,0x55,0xbb, +0xbe,0xd0,0x25,0xf5,0x0a,0x0e,0x11,0x5c,0xd1,0xb4,0x88,0x4d,0x04,0x57,0x37,0xcd,0xf1,0x0a,0xa6,0xea, +0xfa,0x2e,0x16,0x11,0xfa,0xb6,0xc3,0xdb,0xf4,0x4d,0xfa,0xbf,0x39,0xe6,0x40,0xd0,0x0a,0x07,0xe3,0x0d, +0x08,0x46,0xeb,0x3e,0xfc,0x15,0x7b,0x31,0x3e,0xa2,0x0e,0x4e,0x5e,0x63,0x6c,0x03,0x54,0x54,0xeb,0xc0, +0x5a,0x6a,0x6d,0xff,0x26,0x6c,0xa7,0x57,0x97,0xbf,0x03,0xdc,0xe9,0x38,0xb2,0xe5,0x32,0x7f,0x9c,0x2f, +0x5e,0x25,0xe1,0xb3,0xdf,0x66,0xd7,0x1c,0xf1,0xb4,0x5d,0x78,0x87,0x06,0x1e,0x0d,0x72,0x97,0x50,0xc7, +0xdc,0x34,0xf3,0x63,0x7e,0x3a,0xfa,0xbd,0xbf,0xcc,0xe5,0xa7,0x94,0x93,0xc1,0xb9,0xcc,0x70,0xf0,0x30, +0xae,0x16,0x37,0x1b,0x80,0x01,0x5a,0x5e,0x7c,0x62,0x1f,0x18,0xdf,0x45,0xfc,0xf5,0x25,0xf0,0xe5,0x78, +0xfe,0xf6,0x91,0x57,0xac,0xcd,0x81,0xba,0x78,0x55,0xee,0x9f,0x1e,0xb7,0x94,0x3a,0xa8,0xb6,0xed,0xcb, +0xfa,0x49,0xb0,0xb5,0x8a,0xdb,0xba,0x72,0xfa,0x5c,0xb1,0x24,0xf7,0x31,0x1a,0xb5,0xee,0xba,0x06,0x9e, +0xc4,0xf0,0x5e,0xba,0x22,0x77,0xd0,0x6c,0x60,0xf2,0xe9,0x95,0x4b,0x52,0x6a,0xe1,0x77,0xd7,0xe2,0x20, +0x36,0xb9,0xd8,0xbf,0xe3,0x14,0x6e,0x18,0xa9,0xb4,0x43,0x95,0xd1,0xf8,0x40,0xd1,0x04,0x23,0xd3,0x2f, +0xab,0x70,0x76,0x44,0x3a,0xa5,0x74,0xd4,0x45,0xd2,0x8b,0xfd,0x59,0xaa,0x53,0x90,0x9e,0x6d,0xea,0x3c, +0x66,0x87,0x79,0x10,0x54,0x32,0x1f,0x51,0x4f,0xa2,0xbc,0x14,0xb8,0x01,0x3e,0xa4,0x27,0x71,0xba,0x40, +0x90,0x72,0x70,0x12,0x1e,0x54,0xd5,0x08,0x74,0xe8,0x30,0x19,0xa9,0x8e,0x2b,0x65,0x22,0xfa,0x3d,0x3b, +0xe5,0xcc,0xd1,0x7b,0xc6,0xfd,0xcb,0x36,0xcf,0x06,0x2a,0xab,0xb5,0x34,0x14,0x37,0xb4,0xfc,0x9b,0xe1, +0x1c,0x56,0xaf,0xa5,0xbf,0x68,0x33,0x0b,0xce,0xb2,0xae,0x87,0x6d,0xaa,0xe5,0x31,0x42,0x03,0x35,0xc3, +0x34,0x5f,0x76,0xc8,0x33,0x53,0x02,0x1e,0x33,0x90,0x23,0x83,0xde,0x38,0x5a,0x14,0xa6,0xce,0x8f,0xed, +0xe2,0xc7,0x4c,0xe5,0x5c,0xd0,0x78,0x07,0xd6,0x82,0xf5,0xae,0x24,0x42,0x2a,0x7a,0x76,0xa6,0x0e,0x81, +0xd1,0x60,0xc4,0x23,0x79,0xfa,0x82,0x43,0x87,0xa8,0x99,0x33,0x3e,0xc8,0xe2,0xd1,0x92,0xcc,0xdb,0x97, +0x66,0x94,0x97,0x56,0xd8,0x9d,0x73,0x60,0xee,0x9b,0xa8,0xf5,0xce,0x14,0xfd,0x1e,0x3a,0x00,0xcb,0x48, +0xb3,0x91,0x8d,0x2a,0xda,0x18,0x8f,0x6e,0xa1,0x4f,0xdf,0xc0,0xc2,0xc6,0x70,0x44,0xf9,0x43,0x47,0x33, +0xa1,0x29,0xe0,0x8d,0x55,0x6e,0xa4,0x2f,0xde,0x15,0x65,0x6c,0xc4,0x8c,0xa7,0xa2,0xed,0x91,0xa3,0xbb, +0xb1,0xdc,0xf7,0x45,0x51,0x53,0xe2,0x5a,0xec,0x80,0x02,0x83,0x64,0x6c,0xa1,0x6c,0xf5,0x2f,0x67,0xcf, +0xf2,0x05,0x75,0x8b,0xd8,0xb4,0x7c,0x71,0x9d,0xc8,0x49,0xa8,0xb3,0x20,0x16,0x87,0x63,0xd3,0xa5,0xeb, +0xdb,0x70,0xe6,0x2e,0xfd,0x06,0xff,0x5d,0x2a,0x53,0x00,0xc1,0x5b,0x9c,0xe0,0x70,0x47,0x77,0x7f,0x85, +0xd6,0x14,0x00,0xb9,0xe0,0x30,0xd3,0x33,0x9a,0x09,0xc2,0x45,0xc7,0x9c,0x9e,0xd5,0x99,0xde,0x5a,0x05, +0x69,0x59,0x22,0xa9,0x37,0xcd,0xa0,0x9f,0xf0,0x9b,0x7b,0xf1,0xd1,0x31,0x2d,0x88,0x21,0x0d,0x4a,0xca, +0x6f,0x6a,0x28,0x38,0xce,0x05,0x2a,0x0a,0x7e,0x7a,0x1b,0x1d,0x85,0x5d,0x9e,0xba,0x80,0xfa,0x83,0x3b, +0x52,0x57,0x35,0x1d,0x0e,0xac,0x9e,0x39,0xbe,0xdf,0x69,0x08,0xd3,0x41,0x61,0xe1,0x20,0x94,0xda,0x1c, +0xb7,0xf9,0x19,0xde,0x78,0xa0,0x43,0x20,0xf8,0xfc,0x6a,0x41,0x93,0x7f,0x75,0x98,0x97,0xe8,0xf2,0x0d, +0x16,0x0a,0xe0,0x30,0x66,0x9d,0xac,0xff,0xee,0x3a,0xc1,0x6b,0x10,0x5e,0xb6,0x32,0x00,0x90,0x7d,0xba, +0x5c,0xe3,0xcd,0xfd,0x09,0x2b,0xc6,0x6b,0x85,0x61,0x59,0x16,0xae,0xb5,0xbe,0x40,0x99,0x5b,0x45,0x17, +0x85,0x15,0xd6,0xa1,0x03,0xee,0x2f,0x84,0x47,0x54,0x5c,0x08,0xd3,0xeb,0xa3,0xc6,0x30,0xf4,0x2b,0xe6, +0xb6,0x8f,0xe7,0x61,0x12,0x15,0x17,0xc2,0xb4,0xfe,0xb6,0xa1,0x53,0x2f,0x88,0x06,0x8b,0x4c,0xa6,0xfa, +0x7c,0x30,0xd8,0x7a,0x79,0x39,0xb0,0xaf,0xf1,0x6f,0x74,0xfa,0x8b,0xf9,0x13,0x5d,0x93,0xaa,0x1c,0x9d, +0xee,0x05,0xc2,0x19,0x14,0x38,0x34,0x9e,0x3a,0xe3,0x7e,0xe0,0xe1,0xe5,0x1c,0x37,0xb8,0x22,0xe0,0x35, +0x8c,0x25,0x1a,0x86,0x3b,0xd4,0x16,0xcb,0x89,0x1b,0x3a,0x44,0xaa,0xb2,0x0d,0x40,0x8b,0xb9,0xa3,0xd9, +0xbd,0x0b,0x24,0x27,0x80,0xf1,0xe9,0xf7,0x7a,0x77,0x4c,0x7a,0x96,0xd8,0x88,0x91,0x77,0xbb,0xed,0xb1, +0x37,0x1a,0x07,0x1b,0xb4,0xa0,0x20,0x4e,0x2d,0x11,0xc9,0xcf,0xc6,0x86,0x64,0x82,0xda,0xa4,0xca,0xc3, +0xf7,0x63,0xce,0xc7,0x00,0xe6,0x10,0x48,0x19,0xbe,0x25,0x87,0xe8,0x8a,0x31,0xa3,0x79,0xd9,0x01,0x60, +0xd6,0x9f,0x7c,0xfc,0x0a,0x35,0xa5,0x15,0x73,0xa5,0x20,0x38,0x34,0x9c,0x25,0xaa,0xe0,0x54,0xef,0x98, +0xb6,0xaf,0x08,0x8a,0x5f,0x53,0x47,0x1d,0xd5,0x12,0x76,0xaf,0xb7,0xc8,0xa7,0x2b,0x9a,0x7e,0x83,0xf1, +0x65,0xba,0xa6,0xae,0x3a,0xf2,0x10,0x9b,0xf8,0x22,0x7e,0x8c,0xaf,0x89,0xa1,0xf7,0xef,0x91,0x5e,0x40, +0xf0,0xec,0xaa,0x68,0xa5,0x79,0x7a,0xb2,0x7b,0xb0,0x77,0x15,0xc9,0x36,0x24,0x87,0x65,0x6b,0x78,0x80, +0xd8,0xe8,0x50,0xd4,0xa0,0xec,0xc8,0xe7,0x3d,0xfc,0xed,0xfa,0xe9,0x05,0x0c,0x82,0xe5,0x9d,0x98,0xa8, +0xe6,0x0b,0xfd,0xad,0xae,0xe5,0x62,0xf5,0x39,0x6f,0xeb,0x46,0xe2,0xe3,0x86,0xd8,0xf1,0x5b,0xe8,0x70, +0x05,0x21,0x5c,0xc8,0x3f,0x5b,0x0a,0xcc,0xd6,0x42,0xf9,0xb9,0x52,0xa8,0xf8,0x96,0x9e,0x6d,0x6b,0x03, +0x7b,0xe4,0x7b,0xb7,0x8b,0x5b,0x82,0x42,0x65,0xb1,0xc1,0xfb,0x6f,0xbd,0xb4,0xa2,0xcd,0xa6,0x00,0x39, +0x8b,0x98,0x1e,0x3f,0x8b,0x16,0xae,0x22,0x54,0xd5,0x89,0x29,0xb9,0xba,0xcf,0x8f,0xfc,0xf4,0x09,0xc4, +0xdb,0xd8,0xed,0x7a,0x9a,0x1f,0x1e,0xc6,0x36,0x9b,0xc5,0x21,0x37,0x4a,0xce,0x40,0x05,0xd1,0x5f,0x38, +0x1c,0x62,0xa2,0x4b,0x11,0x2f,0x61,0xb8,0x8a,0x3f,0x81,0xbf,0x9d,0x85,0x06,0x77,0xd3,0x69,0xef,0xfc, +0x45,0x0a,0x9d,0x44,0x61,0xa3,0xb9,0x34,0x2f,0xd1,0xb8,0x48,0x16,0x07,0xe9,0x5f,0x65,0x24,0x2e,0x32, +0xfa,0x77,0xe4,0x4d,0x94,0xa6,0x2d,0x08,0xfa,0x15,0xf3,0xc5,0xd2,0x5a,0xd0,0xb4,0x70,0xcc,0xb3,0xf4, +0x36,0x0b,0x11,0x1c,0x91,0x6d,0xa3,0xa9,0xb3,0x8a,0x46,0x88,0x3b,0xe7,0x63,0x30,0x41,0xdc,0xe8,0x7a, +0x66,0x48,0x85,0x56,0xae,0xf0,0x6b,0xe4,0x50,0xe6,0x92,0x29,0x99,0xdb,0x4c,0xb9,0x51,0x3d,0xcf,0x55, +0x92,0x37,0xa9,0x25,0xfb,0x29,0x9f,0x0d,0x90,0x7f,0xac,0xdc,0x9d,0x5c,0x70,0xe9,0x7e,0x55,0x64,0xc0, +0x03,0x73,0xea,0xcb,0x75,0xd7,0x7f,0xab,0x0f,0x69,0x8b,0xe7,0x59,0x73,0x42,0x77,0xfa,0xb3,0x65,0x88, +0xd0,0xa9,0xc4,0xef,0xe2,0xe2,0xd0,0xc6,0x63,0x4c,0x4a,0xf2,0x70,0x25,0x64,0xfc,0xbf,0xff,0xcf,0x00, +0xb9,0x3e,0xa0,0x64,0xf0,0x4a,0x9c,0x48,0xd1,0x2f,0x2b,0x98,0xf4,0x52,0xa8,0xcc,0x12,0x4c,0x78,0xc3, +0xd1,0xef,0xa2,0xa1,0xa9,0x9b,0xae,0x31,0x06,0x3c,0x7c,0xd0,0xf4,0xfe,0x76,0x73,0x19,0x32,0x76,0xd5, +0x81,0xa3,0x5b,0x03,0x1d,0x74,0x2c,0x56,0x7a,0xf7,0xef,0x46,0x45,0x4c,0x9a,0x5c,0x99,0xed,0x00,0x3a, +0x9a,0x7e,0x89,0xdf,0xbb,0x60,0x2d,0x43,0x17,0xab,0x31,0xc6,0x94,0xcf,0x16,0x82,0x3b,0xd6,0x42,0xa8, +0xae,0xfc,0xad,0xc7,0x1a,0xe2,0x31,0x11,0xf0,0x7e,0x55,0xd3,0x74,0x4d,0x84,0x14,0x0c,0x75,0xd5,0x1d, +0x3b,0xbe,0x68,0x98,0x0e,0x8c,0xee,0x80,0xee,0xff,0xa3,0x30,0x13,0xb5,0xdb,0x1d,0x93,0x2e,0xa3,0xb1, +0x0b,0xca,0x86,0xe8,0xf2,0x64,0x29,0xfa,0xf8,0x71,0x6a,0x56,0x0d,0x9d,0xe4,0x1d,0x3c,0xfd,0xda,0x57, +0xf1,0x3a,0x8a,0x17,0x24,0xe4,0x18,0x8c,0x87,0x86,0x66,0x78,0x2b,0xdc,0xe6,0xb1,0xcf,0x4b,0x3e,0x37, +0xbb,0xd0,0xe2,0xff,0xc9,0xb3,0x1b,0x83,0x86,0x7f,0xdf,0xd4,0x2e,0xbb,0xe3,0x65,0x19,0x73,0xe7,0xcc, +0x1b,0x9e,0x0d,0xcf,0x5e,0xb8,0x3d,0x16,0x21,0x95,0xd5,0xe4,0xc2,0xb5,0x6d,0x7a,0x74,0x6f,0xf1,0x4b, +0xec,0x6c,0x90,0x99,0xbc,0xde,0x22,0x3b,0xad,0xfc,0x76,0xf1,0xd7,0xc7,0xaa,0x61,0xb9,0xca,0x84,0xf5, +0xe7,0x1f,0xd5,0x74,0x67,0x40,0x67,0x43,0x8a,0xa6,0xbb,0x5e,0x9a,0x9f,0x64,0xa9,0x0c,0x5d,0x41,0x6e, +0xde,0x8f,0x58,0xc2,0x1d,0x1e,0xd4,0xb3,0x1a,0xa2,0x14,0xc0,0x90,0xa8,0x29,0x21,0x4d,0xbc,0x6a,0x2e, +0x44,0x5b,0x31,0x72,0x4c,0xed,0xed,0x8e,0x4b,0x1c,0x58,0x4a,0x1d,0x19,0x1d,0x0a,0xe7,0x7a,0xca,0xcf, +0x1c,0x86,0x5b,0x3d,0x62,0xfb,0x6f,0x84,0x2c,0x10,0x0a,0x18,0x2e,0x5d,0x46,0x4a,0x01,0x72,0xa6,0x71, +0x87,0x2e,0x82,0xce,0xd8,0xec,0xa4,0xc3,0x91,0x9c,0xa4,0x44,0xa3,0xb3,0xd8,0x57,0xc4,0x29,0x82,0x6e, +0x6a,0xe3,0x96,0xca,0x44,0xca,0x52,0x96,0x56,0x8c,0xac,0x9e,0x55,0x58,0x0c,0x63,0x4e,0xcc,0x64,0x24, +0xbe,0x1c,0xf3,0x92,0xab,0x7e,0x38,0x39,0x0c,0x05,0x63,0xf0,0x1c,0x7b,0x6c,0x69,0x14,0x0e,0xce,0xf7, +0x72,0x58,0x1b,0x53,0x03,0x47,0xc1,0x93,0x61,0x05,0x57,0x42,0xfe,0x1d,0x54,0xf0,0xa2,0xe5,0xf2,0x0c, +0x15,0x5c,0x2f,0xa4,0x82,0xe8,0x21,0xcc,0x37,0xa5,0x02,0x1c,0x02,0xd0,0x00,0xac,0x1a,0x85,0x6d,0x14, +0xd0,0x7a,0x22,0x15,0xdd,0x26,0x37,0x86,0x52,0x6f,0xfa,0xcb,0xcd,0x8f,0x9d,0x03,0x3d,0xcd,0x25,0x78, +0x30,0xde,0x1d,0xf8,0x9e,0x61,0x02,0x53,0x4d,0x2b,0x14,0x7e,0xae,0xb3,0xd4,0x10,0x2c,0x95,0xd8,0xdb, +0x4d,0xcb,0x0b,0x15,0x5c,0x31,0x45,0xa4,0xf1,0xbf,0xc9,0x04,0x9d,0x2d,0x9c,0xa0,0xe8,0x69,0xd2,0x37, +0x9d,0x20,0xdf,0x9c,0xc8,0x2a,0xcd,0xb0,0x77,0x84,0xb9,0x45,0x14,0x29,0xb6,0x3a,0x7e,0xd1,0x26,0xa5, +0x55,0xcb,0x22,0xff,0x75,0x9a,0xe9,0x81,0xce,0xb7,0x44,0xf0,0xe8,0x86,0x98,0x6d,0xb6,0xa6,0xf8,0x44, +0xaa,0xd2,0x54,0xfe,0x4d,0x13,0x47,0xb9,0x8a,0x7d,0x3f,0xd0,0xdb,0xdc,0xd5,0x00,0x93,0x48,0xcd,0x36, +0x83,0x56,0x43,0xf3,0x57,0xfe,0x37,0xd8,0xc2,0xc7,0xf6,0x84,0xa7,0x2d,0xe1,0x67,0x5b,0x3c,0x5b,0x24, +0x93,0x18,0xd1,0xc1,0xf5,0x04,0xbb,0x99,0x9c,0x6e,0x17,0x00,0xb3,0x98,0x42,0x2e,0x44,0x7e,0x67,0x09, +0x3d,0xfe,0xd5,0x32,0x7f,0xe3,0xec,0x30,0xdb,0xf0,0x0d,0x27,0xa6,0x15,0x9a,0x8e,0x8d,0xff,0xda,0xd3, +0x11,0x60,0x00,0xa3,0xb0,0x2d,0x71,0x80,0xe1,0x37,0xbd,0xa8,0x4e,0x6f,0xc9,0x96,0xe6,0x45,0x7d,0xe7, +0xe0,0x54,0xd9,0xbd,0x68,0x9d,0x5f,0xb5,0x4e,0x9a,0xb7,0xc1,0xc6,0x81,0x6d,0xe1,0xd5,0x96,0xeb,0xa5, +0x92,0x72,0xb1,0xab,0x34,0x1c,0x43,0xeb,0x8b,0x9b,0x29,0xe1,0xf7,0x11,0x5e,0x94,0x1a,0x8e,0x41,0xc1, +0x13,0x20,0x74,0x05,0xb4,0xc1,0xae,0x62,0xc1,0xfb,0x3a,0x71,0xef,0x01,0x65,0x3f,0xcb,0xc7,0x23,0xed, +0x94,0x42,0x13,0x5d,0xba,0x16,0xd2,0x3f,0x43,0xc9,0xba,0xbb,0xd8,0xe5,0x3d,0x61,0xbf,0xe4,0x4d,0x43, +0x91,0xcd,0x0e,0xd2,0x74,0x54,0xd7,0xe8,0x62,0x4d,0xd0,0xae,0x75,0x43,0x1c,0xad,0xa4,0x3e,0x6d,0x3c, +0x09,0xed,0x58,0x3c,0xc7,0x35,0xb6,0xcc,0xb7,0x17,0x44,0xf0,0xfc,0x51,0xab,0x7e,0x71,0x22,0x1d,0x8d, +0x88,0xeb,0x92,0xab,0x1b,0xfa,0x28,0x85,0x10,0x59,0x7c,0x72,0x54,0x71,0xfb,0x32,0xdf,0x96,0x60,0xc9, +0xed,0xd2,0x3c,0xa9,0x10,0xef,0x8c,0x47,0xac,0xe0,0xbe,0x04,0x46,0x85,0x27,0xc5,0x4d,0x3b,0xe1,0xb6, +0xf9,0xc5,0xd1,0xd4,0x85,0x7f,0x22,0x8d,0xfb,0xa1,0xa5,0x6f,0xc1,0xe5,0xd7,0xd4,0xb6,0x66,0xeb,0x74, +0xc1,0xab,0xb8,0xc3,0xc6,0xf0,0xe8,0xfc,0x1a,0xbe,0xe9,0xe8,0x04,0xa6,0x0d,0xca,0x96,0x39,0x63,0x28, +0xf0,0xb2,0xec,0xb4,0x33,0xbb,0x07,0xd7,0xc7,0xd0,0xb1,0xad,0xe1,0x45,0xf4,0xc8,0xd2,0x1d,0x1d,0x5b, +0x11,0xa0,0xbb,0xc1,0x8d,0xd4,0x1c,0x68,0x2b,0x82,0xba,0x76,0xfd,0xba,0x25,0x1f,0x35,0x50,0x58,0xe2, +0x79,0x76,0x03,0xa8,0xbc,0x55,0x03,0x76,0xcd,0x10,0x2f,0xf5,0xf4,0x33,0xb7,0x61,0x7c,0x8c,0x63,0x9b, +0x94,0xc2,0x93,0x95,0x00,0xc6,0xef,0x06,0xe9,0x97,0x68,0x78,0xc1,0x99,0xc0,0x20,0xdf,0x4d,0x9a,0x4f, +0xa7,0x8f,0x03,0xff,0xd8,0x04,0x94,0xe1,0xd3,0x41,0x2e,0x7d,0x8c,0xc4,0x19,0xe1,0xcd,0xe2,0x88,0x15, +0x6e,0x5d,0x61,0xbe,0x1c,0xc6,0x18,0x80,0x1b,0xa4,0xe5,0x11,0xe1,0x48,0xc4,0x34,0x9a,0x2a,0xbf,0xae, +0x51,0x1e,0x90,0x50,0x23,0x38,0xd2,0x76,0x74,0xdc,0xb3,0xa3,0x68,0xa2,0x80,0xa4,0xc4,0xf5,0xf3,0x02, +0x3d,0xbb,0xa7,0x17,0x7b,0x98,0x1f,0x54,0x20,0x48,0x5c,0x22,0xbe,0xe4,0x00,0x16,0xac,0x47,0x47,0x9d, +0x26,0x3e,0x8a,0x7e,0xc2,0xc7,0x1f,0x31,0x47,0x3a,0x4c,0x55,0xa1,0xb0,0x91,0xc1,0x3c,0xe9,0xae,0x42, +0x07,0x47,0x2e,0xea,0x37,0x6c,0xbe,0xb2,0xca,0x85,0x2a,0xa6,0x0e,0x13,0xb8,0x1a,0xb8,0xbd,0x81,0x67, +0x89,0x23,0xe7,0x83,0x17,0x67,0xc2,0x73,0x06,0xf7,0xb9,0x8b,0xdd,0x0c,0xa3,0xcc,0x4c,0x6b,0xf7,0xb8, +0xd2,0x68,0x80,0x11,0xc5,0x3a,0xc6,0xf3,0xa6,0x22,0xd7,0x02,0x2e,0x3b,0xb1,0x3e,0x79,0x31,0x9e,0xee, +0x8e,0x07,0x1a,0xbd,0x2c,0xf5,0x10,0x0c,0xfb,0xc4,0x5e,0x21,0x3a,0x23,0x07,0x7d,0x0e,0xe7,0xb9,0x9b, +0xd4,0x04,0x3a,0x52,0xf0,0x2e,0x34,0xdf,0x89,0xe0,0x89,0x17,0x41,0x88,0x0b,0xa3,0xa9,0xf7,0x7f,0x70, +0x50,0xf9,0x3f,0xab,0x07,0xb8,0x84,0x58,0x3d,0x93,0x46,0x6d,0x41,0xa7,0x91,0x5b,0x42,0x96,0x45,0x0a, +0x96,0x16,0x1e,0x57,0x2f,0x54,0x84,0xa8,0x82,0x51,0xe1,0x7c,0x26,0x28,0x54,0x26,0x83,0xe3,0x2c,0xf0, +0x67,0x76,0xbe,0x88,0x25,0x84,0x9b,0xdb,0xac,0x93,0xee,0x71,0x90,0x92,0x41,0x2e,0x48,0xaa,0xc4,0x37, +0xe8,0x94,0xe8,0x26,0x1e,0xf4,0x9d,0xa1,0xc5,0x96,0x10,0x3c,0x72,0xf5,0xdb,0x23,0x7e,0xaf,0x57,0xdc, +0xf9,0x4d,0x70,0xee,0xf2,0x77,0xf5,0x09,0x94,0xd5,0xc7,0xdc,0xbf,0x62,0xd1,0xae,0xb4,0x15,0xfb,0x12, +0xd2,0xc0,0x1b,0xd7,0xff,0x66,0xda,0x88,0xb1,0x08,0xfe,0x87,0x36,0xfe,0x22,0xda,0x08,0x73,0x23,0x9e, +0xc4,0x6b,0x19,0x37,0x7a,0xe9,0xbe,0x9d,0x38,0xa2,0xc6,0xb2,0x00,0xc6,0x2b,0xc1,0xe5,0xcc,0x86,0xa8, +0x53,0xc4,0x18,0xdd,0xf0,0xce,0x9d,0x6b,0x68,0x89,0xe7,0x8e,0x27,0x44,0xf1,0xe1,0x27,0x8a,0x92,0x75, +0xe5,0x7c,0xc4,0xf2,0x94,0x41,0x4b,0x08,0xd1,0xa3,0xad,0x1e,0x8b,0x83,0x93,0xb5,0x11,0x0c,0x96,0x76, +0x09,0x5f,0x92,0x08,0x0e,0x74,0x0b,0x5d,0x64,0xe9,0x63,0x01,0xca,0x89,0x8f,0xd9,0x6c,0x36,0x3a,0x51, +0x4b,0x11,0xac,0x60,0x23,0x2f,0x8d,0xf9,0x61,0x95,0x84,0x59,0xa1,0x62,0xee,0xa6,0xc5,0x97,0x73,0xf8, +0x38,0x8e,0xc7,0x68,0x3c,0xb6,0x56,0x81,0xb9,0xed,0x51,0x6e,0x65,0x3c,0x37,0xfc,0x62,0xa0,0x8d,0xd1, +0xb3,0x24,0xe1,0x83,0x2b,0x73,0xa1,0xf2,0x4a,0xd0,0x2f,0xb1,0x92,0x38,0xec,0x2b,0x9a,0x4a,0xbc,0x34, +0x8b,0x90,0x64,0x21,0x91,0xa8,0x7e,0xec,0x9c,0xb4,0xd1,0xcb,0x6d,0x7b,0x06,0x37,0xda,0x57,0x9e,0xe7, +0x3d,0x58,0x84,0x53,0x75,0xf6,0x3a,0xa4,0xf5,0xa7,0xff,0x9d,0x90,0x86,0x87,0x81,0xa6,0xf2,0x09,0x0b, +0x37,0xa0,0x97,0x95,0xf1,0x25,0x96,0xf8,0xb1,0xea,0xde,0xbd,0x02,0x63,0x43,0xa8,0xb6,0x2a,0xce,0x8a, +0xe5,0x72,0x56,0xfc,0x3f,0xff,0x5f,0x01,0x81,0x57,0x2e,0xb3,0x82,0x42,0x80,0x11,0xfd,0xe5,0x40,0x60, +0x04,0x09,0x7f,0x57,0x46,0x26,0x92,0xed,0xab,0x08,0x4f,0xb3,0xdc,0x55,0xb1,0x58,0xc9,0xd2,0x9f,0xff, +0x0a,0xf8,0x13,0x49,0x22,0x76,0xec,0x21,0xde,0x06,0x71,0x42,0xc9,0x7a,0x59,0x76,0xf8,0x83,0x33,0xba, +0x82,0xd5,0xd5,0x97,0x53,0xe8,0xca,0x10,0x3d,0x13,0x96,0x86,0xc7,0xc4,0x39,0x21,0x33,0xb4,0x86,0x13, +0xde,0x72,0xab,0x6e,0x3e,0xc5,0x6b,0x8c,0x84,0x17,0x89,0x44,0xdf,0x52,0xc4,0xd3,0x39,0x28,0x3a,0x3f, +0x6e,0x2c,0xb9,0x84,0x4e,0x8a,0xc4,0x2b,0x27,0x62,0xa8,0x07,0x25,0xbf,0x9f,0x35,0x77,0xb0,0x0f,0xe6, +0x76,0x6c,0x70,0x4e,0x3e,0x1a,0x9c,0x83,0x69,0x17,0x83,0xe0,0x81,0xb8,0x7e,0x69,0x4e,0xbb,0xe4,0xc6, +0x4d,0x7c,0xfc,0x60,0x75,0xdc,0xd1,0xf6,0x60,0xb1,0x82,0xfc,0x72,0x58,0x8f,0x29,0xc8,0x6b,0x35,0x68, +0x31,0xa5,0xd7,0x8b,0xa1,0x1d,0x2e,0x83,0x56,0xa2,0xaa,0x20,0xb8,0x79,0x85,0x04,0x16,0x57,0x97,0xcd, +0xd5,0x6e,0xe5,0x7c,0x3e,0x79,0x05,0xe0,0x00,0x5a,0x5b,0xb5,0xf3,0xba,0xa5,0x29,0x53,0x5d,0xbf,0xd3, +0x40,0x8e,0x61,0x22,0x6a,0xda,0xa2,0x5a,0x04,0x45,0x31,0x53,0x7e,0x6e,0x2e,0xb8,0xfe,0xcb,0xd4,0x47, +0xa6,0xfc,0xf9,0x60,0xdd,0xec,0xb8,0x8b,0x4d,0x92,0x28,0x5b,0x11,0x71,0x25,0xe9,0x62,0xba,0x94,0x5e, +0x4f,0x97,0xd3,0x1b,0xe9,0xcd,0x45,0x4c,0xa3,0x24,0xc3,0x55,0x8c,0x9b,0xb4,0x02,0xb1,0xda,0x63,0xdb, +0x82,0x71,0xa6,0x95,0x22,0xfd,0xba,0x1c,0xeb,0x2e,0xfc,0x24,0x25,0x2f,0xba,0x2c,0xeb,0xc4,0x13,0x77, +0x8c,0x49,0x24,0x42,0x6d,0x45,0xac,0xf2,0xe3,0x09,0x6f,0x33,0x9b,0xd1,0x9b,0x42,0x56,0x71,0x1b,0x3f, +0xcf,0xc3,0xfc,0xfc,0xd1,0xf1,0xfc,0x2b,0x26,0xc7,0x71,0x1c,0x03,0x23,0xbb,0x94,0x21,0x6b,0xa9,0xd7, +0xe4,0x19,0x22,0x5c,0xf5,0x6a,0x6b,0xa4,0xb9,0x25,0x41,0xac,0x51,0x82,0x63,0xed,0xc6,0x85,0x35,0xb1, +0x1b,0x6b,0xd0,0x9c,0x5e,0x18,0xce,0xc4,0x2f,0xb5,0x59,0x92,0xf9,0xf2,0x92,0xd2,0x87,0x2d,0x8c,0x71, +0x5a,0x1a,0x6d,0x5b,0x86,0xd5,0xc6,0x92,0x59,0x07,0xe0,0x32,0x2b,0x3f,0x21,0x35,0x24,0x53,0x06,0x4b, +0xe0,0x2e,0x15,0xbf,0x84,0xd7,0x09,0x09,0xe0,0xc8,0xdc,0xd0,0x11,0xc4,0xdf,0x9e,0x9a,0x86,0x9f,0xff, +0x6a,0xc5,0xe9,0x79,0x86,0x3d,0xf3,0x29,0x59,0x4d,0x98,0x94,0xcb,0x21,0xfe,0xbc,0x22,0x5a,0x69,0xe0, +0x6f,0x84,0xd6,0xe2,0x1c,0x5a,0x69,0xd2,0xde,0x52,0x60,0x87,0x5c,0x89,0xa2,0x98,0x41,0xcb,0x5d,0x78, +0x15,0x5f,0xbf,0x59,0xc5,0xcb,0x13,0xd0,0x6d,0x7e,0x8f,0x7d,0xb4,0x2e,0xf9,0x7b,0x64,0x0c,0xc7,0xba, +0x46,0xb1,0x05,0xb6,0x23,0xf3,0x52,0xf7,0x68,0xcc,0x98,0x94,0xe4,0xde,0xd9,0xc1,0x69,0xe8,0x6b,0x7f, +0x64,0xd8,0xfe,0xf7,0xd4,0x6f,0xba,0x52,0x1b,0x98,0xde,0x10,0xaf,0x88,0x8a,0xb8,0xcb,0x96,0xd0,0x8e, +0x14,0x15,0x44,0x63,0xc5,0x26,0xe2,0x38,0x47,0x9d,0xdd,0x46,0xb5,0x9c,0x77,0x88,0x42,0xcb,0xb8,0x47, +0x9b,0x12,0x32,0xe1,0xc9,0xe1,0x1e,0x5d,0xab,0xbb,0x20,0x74,0x5d,0xb0,0x99,0xb9,0x72,0xcf,0x25,0x88, +0x59,0x05,0x4f,0x67,0x63,0x93,0xed,0xa3,0xfe,0x06,0xa2,0xa8,0x8d,0x38,0x4c,0xed,0xd8,0xd6,0xbf,0x3c, +0x65,0x84,0x9f,0x97,0xa0,0xea,0xc4,0x76,0x86,0x64,0x19,0x2d,0xc1,0x68,0x51,0x2e,0x76,0xf2,0x57,0xa0, +0x80,0x14,0xe6,0xa4,0x9b,0x8a,0xa0,0x61,0x95,0x25,0x27,0xa1,0x82,0xdd,0x7f,0x1e,0x52,0x18,0x96,0x32, +0xba,0x20,0xb6,0x90,0x92,0xfc,0x2e,0x73,0x14,0xc7,0x64,0xc4,0x5d,0x71,0x80,0x6f,0x79,0xfb,0xf8,0xe2, +0x8b,0xc7,0xf3,0x01,0x1b,0x59,0x72,0x01,0xf9,0x5f,0x35,0x32,0xc5,0x9d,0x59,0xdd,0x57,0x91,0xb0,0x3f, +0xb4,0x03,0x6b,0x12,0x47,0xc4,0x6d,0x3a,0x64,0xb8,0x90,0x7a,0xa1,0x96,0xee,0xb8,0xab,0xae,0xca,0xd7, +0x0f,0xf5,0x74,0x2e,0x21,0xe1,0xeb,0x17,0xec,0xa9,0x85,0xd9,0x45,0x16,0xaf,0x58,0x76,0x39,0xc4,0x73, +0x9a,0x91,0x94,0x12,0x75,0xf9,0xca,0x9d,0x2b,0xbd,0x78,0x01,0x87,0x45,0x8e,0xc8,0x18,0xf3,0xf6,0xc2, +0xf6,0x45,0x22,0x75,0xa1,0xa2,0xa9,0x08,0x00,0x0f,0x34,0x39,0xf1,0x51,0xf0,0x2a,0x7e,0xe9,0xc7,0xae, +0x99,0x65,0xa2,0x57,0xce,0x8f,0xf3,0x96,0xb8,0xf0,0x1b,0x7d,0x23,0x74,0x70,0x8b,0x2b,0xc0,0x84,0xdf, +0xc1,0xab,0x50,0xb1,0x18,0x98,0x88,0x85,0xb7,0x04,0x75,0xfe,0x91,0xfe,0xff,0xaa,0x34,0x24,0xe7,0x58, +0xb8,0x60,0xe6,0x40,0x3c,0xaa,0x48,0x4a,0x54,0x5e,0x41,0x3d,0xa1,0xd4,0x05,0xff,0x7d,0xc8,0x27,0x04, +0xf6,0x6f,0x21,0xe5,0x2d,0xe8,0x88,0xd2,0xff,0x5c,0xec,0x35,0xde,0x12,0x7f,0x4d,0x6c,0x73,0xd5,0x74, +0x40,0xb4,0x25,0x3b,0xed,0x8e,0x32,0x40,0x22,0xf6,0xd8,0x03,0x73,0xdd,0xb4,0xbb,0x77,0x02,0x59,0x2c, +0xe5,0xee,0x5b,0xe6,0x58,0x8c,0x31,0xfb,0x64,0x03,0xc3,0x41,0x09,0x11,0x99,0x07,0xb2,0xd6,0x78,0x83, +0x60,0x83,0x61,0x7e,0x51,0x79,0x04,0x88,0xc6,0x20,0x99,0x72,0xe2,0x63,0x38,0x82,0x85,0x57,0x08,0x0a, +0x44,0x9c,0x1a,0xa1,0xd4,0x33,0xf3,0x53,0xb3,0xdf,0xbe,0xfe,0x6f,0x3b,0x35,0x91,0xe1,0xb0,0xec,0xcc, +0x6f,0x3a,0x1a,0x9e,0xf0,0xf9,0xfd,0xef,0x4c,0x25,0x87,0xcb,0x9d,0x1b,0x7a,0x2d,0xb1,0xb5,0xb5,0x60, +0x36,0x57,0x9d,0x42,0xca,0xf1,0xec,0xbe,0x29,0x6f,0xa2,0x16,0x95,0x64,0x13,0xe3,0xbc,0x3f,0x0c,0x54, +0xc7,0xd9,0x56,0x6e,0x54,0x67,0x98,0x7a,0x16,0x05,0x05,0x8c,0x59,0x67,0xce,0x61,0x3c,0xee,0xb3,0x9c, +0x9e,0x19,0xe0,0x0b,0x46,0xcf,0x3e,0xae,0x8e,0x84,0xbf,0x82,0x47,0xbf,0x31,0x6b,0x96,0x7d,0xb7,0x62, +0x4f,0xce,0x67,0xd1,0x8c,0x18,0x8a,0xe5,0x8d,0xd5,0x19,0xd1,0x0b,0xb9,0xb1,0xd1,0xc3,0x6b,0xbe,0x99, +0x4e,0x64,0x4f,0x2d,0x8c,0x10,0x67,0x25,0xd9,0x07,0x31,0x0e,0x76,0xb9,0x29,0xff,0x2a,0xdf,0x56,0x0a, +0x25,0x3b,0xb6,0x36,0x03,0x65,0x99,0xb2,0x0a,0x7f,0x7c,0xd7,0x1b,0x5b,0x64,0xaa,0x24,0xf5,0xb4,0x97, +0x7a,0x4c,0xe0,0x16,0x92,0xeb,0x39,0x06,0x18,0x2c,0xdb,0x09,0xbb,0xf3,0x03,0x2d,0x97,0x5a,0x0d,0x1b, +0xb0,0x7b,0x5c,0x67,0xff,0xf0,0x61,0xc1,0x87,0xac,0x7e,0x8f,0x87,0x7e,0xdd,0x4f,0xe1,0x9f,0x35,0x3d, +0xab,0xd9,0xdd,0xf1,0x10,0x06,0xf5,0xc9,0x83,0x6e,0xde,0xe5,0x53,0xd5,0xa0,0xd7,0xd4,0xa3,0xd1,0x4b, +0xbe,0x0b,0x8a,0xa4,0xbc,0x81,0x63,0x4f,0x29,0x78,0xb2,0xe5,0x38,0xb6,0x93,0x4c,0xfc,0x38,0x1f,0x63, +0x6e,0x3c,0x1e,0x0e,0x81,0xe1,0xa2,0x53,0x90,0x74,0x78,0x95,0x39,0x86,0x2c,0xaa,0x8a,0xa8,0x99,0x48, +0x6d,0x3b,0xba,0x47,0x9a,0x36,0x34,0xfb,0x54,0xa5,0xbf,0x93,0x09,0x4c,0xf3,0x4c,0xf7,0x65,0x26,0xde, +0x09,0x70,0x59,0xfd,0x4f,0xec,0x9f,0x2a,0xc6,0x0d,0xa7,0x97,0xa0,0x41,0x7c,0x52,0xf8,0x47,0xaf,0xe6, +0xfd,0xfa,0x65,0xe9,0xdb,0x13,0xd5,0x51,0xac,0x9a,0x97,0x65,0xe1,0x9e,0x2d,0x53,0x47,0x20,0x92,0x09, +0x86,0x58,0x00,0xc6,0xca,0x22,0x95,0xd4,0xa0,0x4e,0x16,0xa3,0x81,0xb3,0xea,0x08,0xf3,0xa0,0x37,0x07, +0x86,0xa9,0x25,0xad,0x54,0x76,0xa4,0xe2,0xe9,0x18,0x8c,0xb5,0xcb,0x62,0xc0,0xeb,0x44,0x17,0x5f,0x9e, +0xfc,0x0e,0x1d,0x44,0x0f,0x76,0xe3,0xd5,0xde,0xbd,0x43,0xbc,0xb3,0x9d,0x82,0x84,0x61,0x29,0xf0,0x4b, +0xcf,0xb2,0x9f,0x69,0xab,0xd6,0xd7,0xb3,0x38,0x34,0x28,0xce,0x51,0x90,0x10,0x6d,0xc0,0xa0,0x6b,0xd6, +0x87,0x0f,0xef,0xa0,0x84,0xe1,0xde,0xd0,0x80,0xa1,0xd4,0x87,0x0f,0xc9,0x04,0x30,0x04,0x50,0xb5,0x6a, +0xf0,0xf9,0xd7,0xaf,0x3c,0xfc,0x03,0x83,0x12,0xca,0x85,0x3f,0xaf,0xde,0x87,0x0f,0xde,0xc7,0x3c,0xfc, +0x05,0x44,0x8a,0x9d,0x4a,0xb0,0x19,0x0c,0x19,0x1c,0xe3,0x7a,0xd6,0x82,0x81,0xe0,0x8e,0x24,0xc2,0x25, +0x9e,0xb3,0x9e,0x7d,0x84,0x07,0x12,0x9a,0xaa,0xab,0x27,0x53,0xd8,0x47,0xf8,0x4d,0xd0,0x9a,0x8d,0xad, +0xa5,0x2d,0xbf,0x3d,0x02,0x77,0x57,0xcc,0x89,0x97,0xfa,0x04,0x2f,0xfa,0x8e,0x3e,0x82,0x62,0xd2,0x4c, +0x39,0xa2,0xfc,0xbb,0x77,0x30,0x0d,0xaa,0x69,0xe2,0xbb,0xb4,0x9e,0xc2,0x31,0x3f,0xa5,0xaa,0x1e,0x01, +0x82,0xbe,0xcc,0xd8,0xea,0x01,0xf0,0x08,0x19,0xaf,0x93,0xc0,0x59,0xb7,0xfa,0x01,0xad,0x78,0xcb,0xeb, +0xba,0x3a,0xeb,0xd8,0x83,0x6e,0x3f,0x66,0x0a,0xbc,0x95,0x3b,0x18,0xba,0xee,0x7a,0x1c,0x70,0x96,0xbb, +0x00,0x8b,0xc0,0x08,0xab,0x49,0xaf,0x16,0x7a,0x97,0x4a,0xbf,0xb4,0x83,0x0f,0x1f,0x0a,0x00,0xb1,0xee, +0x8f,0xee,0x29,0x25,0x61,0x52,0x65,0xf3,0xd2,0x83,0x95,0xb3,0x9d,0xd4,0x6b,0xfa,0x37,0xef,0x3b,0x4c, +0x37,0xd6,0x0b,0x2a,0x6c,0xfb,0x2b,0x45,0x0f,0x2a,0xba,0x01,0xb1,0x3d,0x3e,0x6d,0x07,0xf3,0x80,0x19, +0xc6,0x92,0x7a,0x76,0xa8,0x82,0xc2,0x9f,0xfc,0xa9,0xa7,0x7e,0xfd,0xfa,0xf6,0x5d,0x9e,0x04,0x98,0x34, +0xef,0x9b,0xf5,0xbd,0xf6,0x2e,0xff,0x94,0x4a,0x7b,0x41,0x7b,0x63,0x19,0xc3,0xc1,0x6b,0x13,0x5f,0xb3, +0x35,0x2e,0xbd,0xed,0xb2,0xf9,0xc7,0x19,0x45,0x10,0x8c,0x6d,0xcf,0x99,0x3d,0x02,0x2d,0x85,0xe9,0xc0, +0x80,0x31,0x8c,0x1c,0x7b,0x68,0xb8,0x7a,0xea,0x93,0xc1,0x67,0x3c,0x95,0xc5,0x3c,0xe8,0x80,0xea,0x6c, +0x4f,0x35,0x4c,0x58,0x3f,0xd5,0xd8,0x7a,0x18,0xa4,0x1c,0x54,0x22,0x62,0x03,0x02,0x51,0x31,0x09,0x7f, +0x72,0x62,0x1b,0x9a,0x92,0x4f,0x7f,0xd3,0xbf,0x67,0x41,0x70,0x75,0xf5,0xa4,0x03,0x18,0xed,0xd2,0x80, +0x01,0x58,0x6b,0xae,0x54,0xea,0x29,0x80,0xbc,0x97,0x84,0x12,0x62,0x09,0xb7,0x26,0xb0,0xa4,0x8f,0xf0, +0x8e,0x5b,0x0b,0x26,0x37,0xb1,0x73,0x7a,0xdc,0x64,0x09,0x0c,0x8f,0x90,0x13,0x6b,0x89,0x74,0x2f,0x95, +0x5e,0x50,0x16,0x79,0x35,0x7d,0xef,0x63,0x01,0x55,0x9b,0xc9,0xcb,0x63,0x94,0x44,0x9c,0x19,0x2e,0xb2, +0x54,0x15,0xd6,0x30,0x52,0x10,0x7f,0x5c,0x1b,0x65,0xc7,0x86,0xb6,0xb6,0x16,0x14,0xd6,0x02,0xc4,0x27, +0x3c,0x67,0xac,0xe3,0x1a,0xd7,0x61,0x71,0xb3,0xb0,0x04,0x24,0x04,0x5c,0xfe,0x78,0x57,0x10,0x7d,0xf9, +0x84,0x4f,0x55,0x5c,0x03,0x6b,0xfa,0x5a,0x22,0xf1,0x69,0x4d,0xaf,0x1e,0x73,0xf2,0x05,0x2c,0x63,0x82, +0xfd,0x2c,0xe5,0x00,0x85,0x5f,0x55,0x99,0x01,0x0c,0xc4,0x92,0xc5,0x09,0x73,0xb6,0x81,0x8b,0x33,0x04, +0xd5,0x62,0x28,0x34,0x05,0x5f,0x1d,0x90,0x58,0xa8,0x26,0x26,0xd6,0xbc,0x2c,0xbf,0x30,0x27,0x79,0xa0, +0xa7,0x13,0x99,0x7f,0x7c,0x48,0xa4,0xc2,0x7c,0x01,0x38,0x1a,0x2c,0x09,0xdd,0xab,0x7b,0xb0,0x18,0x3b, +0x63,0x0f,0x27,0x24,0x2d,0x56,0xa6,0xcf,0x9c,0x90,0xf0,0x80,0x4a,0xac,0x1a,0x31,0x4d,0x36,0x5d,0x46, +0xea,0xf1,0xe9,0x42,0xcf,0xba,0xba,0xc7,0xa1,0x7b,0xd2,0xd1,0xb5,0x69,0xd5,0x18,0x6c,0x82,0xac,0xad, +0x60,0x18,0xfd,0x08,0xe5,0xa5,0xed,0x5a,0x21,0xad,0xd6,0x8a,0xf9,0xb4,0x5b,0x73,0x3e,0xf9,0x74,0xee, +0x93,0xb2,0x93,0xed,0x8e,0x1d,0x98,0x9b,0xea,0xfc,0x27,0x98,0x94,0xae,0xeb,0x52,0x7b,0x89,0x44,0xea, +0x29,0x3d,0xae,0xb9,0x30,0x16,0x13,0xd1,0x61,0x7d,0x2b,0x7d,0xff,0xf5,0x2b,0xc9,0x4a,0x9c,0x10,0x97, +0x85,0x85,0xf9,0x29,0x91,0xa8,0x26,0x46,0xf7,0x89,0x54,0xba,0x5b,0x8b,0x7e,0x83,0x09,0x83,0x2f,0x30, +0x5b,0xe6,0x87,0x0f,0x6b,0x63,0x58,0xc2,0xff,0xc0,0x29,0xd7,0xbb,0xc9,0xa0,0x97,0x54,0x0a,0xb1,0xde, +0xfd,0xf0,0xa1,0x0b,0xad,0x63,0xc9,0xd4,0xa3,0x59,0x33,0x7f,0xfd,0xc2,0x9f,0x80,0x42,0x8b,0x56,0x6a, +0xb7,0xb6,0x36,0xfe,0xf5,0xab,0xb0,0xad,0xd9,0x8a,0x5d,0xb3,0xa1,0xd5,0x6c,0x39,0x91,0xee,0xe6,0x6a, +0x36,0x12,0x1a,0x25,0x7e,0x25,0x80,0xbb,0x6b,0x66,0x6a,0x7b,0x0a,0x12,0x48,0x4f,0xda,0xd0,0x54,0xd2, +0x46,0xd8,0x73,0x63,0xce,0x3a,0xec,0x0f,0x1f,0x32,0x19,0x35,0xf5,0x24,0xd0,0x07,0x04,0x04,0xed,0x76, +0x7f,0xfd,0xc2,0xb6,0xf3,0x69,0xa3,0x66,0x7d,0x2b,0x7c,0xff,0xd4,0x5d,0x4b,0xe2,0xbf,0x6b,0x85,0xd4, +0x7f,0x58,0xdf,0x8a,0xdf,0xab,0x6b,0xf8,0x77,0xda,0x81,0xc2,0x4e,0x16,0x33,0x34,0xd4,0xcc,0xb4,0x93, +0xa5,0xeb,0x56,0x6a,0x5d,0x78,0x02,0x61,0x58,0x33,0x52,0xa9,0xb4,0x11,0x4c,0xc6,0xc4,0xe7,0x41,0x44, +0x02,0xa0,0xe0,0xe8,0xce,0x0e,0x17,0xef,0x69,0xa7,0x16,0x48,0x16,0xe8,0xf2,0x8b,0xfe,0xcd,0xf9,0x2e, +0x26,0xd4,0xf8,0x64,0x20,0x63,0xb5,0xb2,0xa8,0xdc,0x84,0x25,0x6d,0x44,0x3e,0x3b,0xd8,0x63,0x8d,0x23, +0x11,0x26,0x4a,0x33,0xdc,0x11,0xfa,0x1c,0x80,0x77,0x2d,0x12,0xc9,0x1e,0x10,0x9f,0x05,0x3c,0x06,0x97, +0x8b,0x01,0xa3,0x31,0x84,0x7d,0x93,0x4a,0x13,0x10,0x35,0x23,0x6d,0x48,0x0b,0x63,0x16,0x70,0x60,0x52, +0x11,0x40,0x24,0x19,0x35,0x98,0x09,0xbb,0x96,0x07,0xc2,0x12,0x52,0x7b,0xdb,0xfe,0x43,0xdd,0xb6,0xd7, +0xd6,0x52,0x30,0xac,0x6f,0xf6,0x77,0xc2,0xcc,0x0c,0x95,0xab,0xa4,0x55,0xe3,0xcf,0x59,0x0e,0x5b,0xda, +0xfb,0x94,0xf4,0x01,0x40,0xdc,0x1b,0x50,0xa1,0x76,0x46,0x4b,0x24,0xe9,0x48,0x43,0x00,0xb5,0x04,0xd6, +0x72,0x1a,0x3f,0x03,0xb1,0x45,0x5a,0xa9,0x01,0x4d,0xc2,0x40,0xb0,0x8d,0xc8,0x97,0x0f,0x1f,0xfe,0xc4, +0x15,0x26,0x1a,0x9e,0x20,0x8e,0x40,0x12,0x52,0x8f,0xef,0xa4,0x1e,0xd9,0x9b,0xf4,0x19,0x5b,0x5f,0x52, +0xc7,0xb0,0xce,0x80,0x16,0x71,0xc0,0x30,0x46,0x7f,0x60,0x08,0xcb,0xbb,0x1a,0xd6,0x84,0x06,0x70,0x8c, +0x11,0x78,0xf0,0x4b,0x9c,0x20,0x1a,0x32,0xfc,0x11,0xee,0xfc,0x05,0x5b,0x8b,0xd3,0xe3,0x08,0x03,0x7c, +0x62,0xdd,0xc6,0xec,0x52,0xed,0x23,0x6d,0x7c,0x8a,0x7f,0x9d,0x44,0x05,0xe7,0x3f,0x12,0x30,0xb0,0xd8, +0x96,0x7e,0xa2,0x92,0xc9,0x52,0xdc,0xd8,0x4e,0xdd,0x34,0x3f,0xcd,0xbf,0xf2,0x5b,0x80,0xc9,0xf4,0x79, +0x1d,0xbc,0x03,0x2d,0x89,0x69,0x43,0x28,0xec,0xe9,0x46,0x8f,0x24,0x08,0x09,0x14,0x30,0x12,0x9f,0xb9, +0x8f,0x50,0x05,0x10,0x83,0x13,0x10,0x83,0xf5,0x87,0xb3,0x6d,0x01,0xce,0x38,0x6e,0x75,0x10,0xa8,0xe9, +0x44,0xdf,0xb4,0x3b,0xaa,0xd9,0x9a,0xa8,0x66,0x22,0xfd,0x0e,0xfa,0xe1,0x33,0xee,0x45,0x3f,0xca,0xe2, +0xbf,0x23,0xd8,0x19,0x90,0xa4,0xdf,0x99,0x9d,0x56,0xd3,0x6e,0x7a,0x9c,0x36,0xd3,0xdd,0x74,0xcf,0xd7, +0x58,0xc5,0xc2,0xda,0x75,0xd4,0x3e,0x2d,0x8d,0x54,0x7a,0x84,0x74,0xaa,0x01,0x68,0x83,0x00,0x34,0xed, +0x0f,0xf8,0x3f,0x80,0x06,0xac,0xc6,0x06,0x52,0xd5,0x80,0x90,0x99,0xc2,0x68,0xe3,0xab,0xc0,0x14,0xf0, +0x95,0x50,0x3b,0x95,0xf2,0xf1,0x30,0x4a,0xdb,0x81,0x12,0x06,0xf3,0x5d,0xb5,0x53,0xdb,0xc4,0x91,0xa1, +0xea,0x39,0x97,0x32,0x50,0x9e,0x20,0x55,0x6b,0xea,0xaf,0x5f,0xbd,0xd0,0xe2,0x9d,0x53,0xae,0xc1,0x06, +0x42,0x2a,0x76,0x6b,0xc9,0x6b,0xce,0x0e,0x6d,0x54,0x48,0x12,0x09,0x20,0xec,0xef,0x29,0x60,0x3e,0x11, +0x41,0x32,0xae,0xdd,0xea,0xdf,0x5c,0x58,0x0d,0xb7,0x7a,0xf6,0x4f,0x9e,0x19,0x2a,0xad,0x66,0x0d,0xb0, +0xe3,0x9d,0xfd,0xcb,0xe3,0xa3,0xda,0x18,0x19,0x16,0x80,0x3b,0xf0,0x86,0x26,0xe5,0x99,0x26,0xb5,0xcc, +0x4e,0xad,0x8d,0x91,0x77,0x75,0xe1,0x7b,0xfe,0xfb,0x76,0x37,0x93,0xd9,0x4e,0x01,0x78,0x59,0x30,0xda, +0x3c,0x82,0x6c,0x5b,0x1a,0xa1,0x9a,0xed,0xe2,0x2b,0x3a,0x78,0x93,0x82,0x15,0xde,0x03,0xe5,0xce,0xe1, +0xe5,0xe0,0x23,0x1a,0x01,0x5c,0x0b,0x80,0x25,0xc8,0xe4,0xd1,0x28,0x3b,0x1a,0xbb,0x03,0x7f,0x78,0x97, +0x50,0x04,0xab,0x23,0x2a,0x68,0x19,0xf5,0x22,0xb5,0x70,0x4e,0xb6,0xed,0xda,0xe8,0x1b,0x4c,0xc4,0xf7, +0x6d,0x92,0xa6,0x4c,0xc7,0xb1,0xea,0xa8,0xc5,0x27,0x6d,0x10,0x5f,0xa0,0x1c,0xa6,0x80,0x3b,0x19,0xac, +0x69,0x09,0xcf,0x26,0x71,0x3b,0x68,0x0b,0x73,0x2f,0x24,0xed,0x08,0x57,0xb5,0x11,0xe4,0x61,0x32,0x8c, +0x77,0x1b,0xc5,0x2d,0xb7,0x63,0xd2,0x20,0x80,0xee,0x93,0x2a,0x08,0xe5,0x14,0x82,0xd6,0x25,0x48,0xd4, +0x6f,0x5d,0x82,0x64,0x4f,0xcc,0x21,0x4d,0x3d,0x2c,0x8f,0x04,0xb0,0x11,0xcb,0x07,0x81,0xaf,0xde,0x5e, +0x40,0x9f,0x53,0x5f,0x5c,0x82,0xbe,0xe8,0xbf,0xbd,0x0c,0xde,0x16,0x82,0xb7,0xcd,0x24,0x93,0xf0,0x82, +0x07,0xe8,0x59,0xdc,0x55,0x9b,0x08,0x6a,0x08,0x34,0x34,0x49,0x1d,0x6b,0x05,0xf4,0x0f,0x43,0x23,0x26, +0x02,0xb4,0xbf,0x1d,0xa2,0x54,0xa1,0xd9,0x83,0x9d,0x17,0xd5,0xf6,0x91,0xd7,0x39,0x35,0x07,0x18,0x69, +0x5a,0xe8,0x0c,0x6c,0x46,0x5c,0x3a,0x88,0x97,0xc2,0xe6,0x5d,0x6a,0xde,0x03,0xb2,0x4a,0xdb,0x12,0xff, +0x82,0x2e,0x90,0xe3,0x01,0x77,0x05,0x0c,0xd0,0x83,0xf1,0x09,0x44,0x05,0x94,0xad,0xf9,0x4d,0x55,0xf9, +0x07,0x54,0xc0,0xe6,0xd4,0x19,0x2c,0xed,0x40,0x69,0x51,0x96,0xff,0x94,0x20,0x41,0xc9,0x55,0xab,0xbd, +0x83,0x79,0xae,0x5d,0xfa,0xd3,0xfb,0xce,0x48,0x09,0x18,0x04,0x30,0xa8,0x7c,0x81,0xc8,0x86,0x15,0x05, +0x92,0xa9,0x16,0x63,0x54,0x00,0xdd,0xa6,0xb2,0x76,0xaf,0x07,0xaf,0x80,0x42,0x99,0x7a,0x4b,0x66,0xb0, +0xea,0xf4,0x89,0x2c,0x5c,0x50,0x5f,0x8c,0x6c,0x1f,0x34,0x4b,0xa0,0x7a,0xfc,0x07,0xe4,0x09,0x7b,0x40, +0x62,0xea,0x93,0xc6,0x99,0x42,0x5d,0x96,0xac,0x03,0x49,0x15,0x42,0xc5,0x14,0x15,0xdb,0xac,0xaa,0x69, +0xac,0x49,0x0f,0x66,0xc2,0x41,0x4d,0x4c,0xe2,0x52,0x77,0x21,0xe3,0x11,0x99,0x67,0xc2,0xc3,0x00,0x2f, +0xa4,0x1e,0x23,0x59,0x40,0x95,0x43,0x32,0xde,0x3c,0x50,0xd4,0xa5,0x25,0x05,0x4a,0x6d,0x02,0x59,0x6d, +0x32,0xf1,0xd1,0x43,0x71,0x9f,0x00,0xcb,0x08,0x56,0xe9,0xaf,0x5f,0x7a,0x55,0x92,0x22,0x6d,0xd9,0xfc, +0x20,0xea,0xac,0x25,0x99,0x44,0x8a,0xea,0x96,0x09,0xfc,0x08,0x5c,0x65,0x2d,0x91,0x4b,0xac,0xb1,0xa2, +0x69,0xa9,0xa1,0x93,0xc0,0x2e,0x32,0x3c,0xc6,0x73,0x58,0xa1,0xc0,0xdd,0xf0,0x89,0x77,0xe0,0x01,0x33, +0xa9,0x0a,0xdd,0x61,0xae,0x03,0xb9,0xd1,0x1d,0x49,0xc6,0x31,0x5a,0x15,0x2c,0x1a,0x49,0xb5,0x50,0x93, +0xc7,0x4f,0x1e,0x12,0xe0,0xfd,0x03,0xd5,0xc5,0x6c,0xb2,0xcc,0x7c,0xb7,0x51,0xfe,0xab,0xdd,0xae,0x8e, +0xaa,0x20,0x2e,0x61,0x2e,0x39,0x68,0x41,0x9b,0x35,0x9b,0xcd,0x82,0x0b,0xac,0x55,0xe3,0x47,0x2c,0xa1, +0xbe,0xa5,0x99,0x3a,0xcc,0x37,0xfb,0x84,0x56,0x1e,0x52,0xb6,0x81,0x94,0x6d,0xd2,0xda,0x66,0x42,0xc9, +0xfc,0x66,0x7c,0x8f,0xca,0xa5,0xf0,0xb4,0x02,0xbc,0x58,0x08,0xe4,0x50,0x0a,0xb5,0xed,0x10,0x60,0x6e, +0xed,0x42,0x06,0x6c,0xcc,0x4c,0x15,0xe0,0x63,0x5a,0xf2,0xf1,0x29,0x0d,0x0c,0xf2,0x42,0x00,0x3a,0x4e, +0xc9,0x76,0xd4,0x0f,0x09,0x23,0x7c,0xf0,0xf3,0x2e,0x84,0xed,0x04,0xb9,0xb7,0xb8,0x1e,0x74,0x25,0xcc, +0x14,0x36,0x1d,0x9f,0x80,0x9d,0x62,0xd0,0x8f,0xae,0xc1,0x0c,0xf3,0xa7,0x2a,0xaf,0xc0,0xd4,0x98,0x84, +0xc8,0xcb,0x49,0xbf,0x81,0xa4,0xbd,0x2c,0x97,0x09,0xd7,0xb4,0x55,0xab,0x87,0x7e,0x4a,0xf4,0x5a,0x27, +0xae,0x42,0x32,0xd5,0xab,0xd9,0x3a,0x5f,0x31,0x20,0x2b,0xbd,0xd4,0xf6,0xbc,0x80,0xcd,0x83,0x1c,0xf5, +0x9d,0x33,0x5a,0x6d,0x94,0x29,0x80,0x3c,0xf5,0x80,0x44,0xd3,0xfd,0x5a,0xd8,0x30,0x1d,0x90,0x06,0xdf, +0xff,0xf5,0x6b,0xf4,0xb1,0x00,0xe0,0x45,0x59,0xc2,0xe0,0xc3,0x87,0x77,0x1a,0x1f,0x4b,0xd3,0x04,0xe5, +0xeb,0xc3,0x07,0xc7,0x63,0x63,0x1e,0xa4,0xfc,0x55,0x1f,0x59,0x83,0xdc,0x22,0x03,0x59,0x9d,0xd5,0x7f, +0xc2,0xaf,0xed,0x3e,0xcc,0x0a,0xf6,0x5e,0x1b,0x70,0x4f,0x02,0xae,0x4a,0x0b,0x04,0x33,0xca,0xbc,0x24, +0x68,0x6e,0xe9,0x3a,0x08,0x10,0x36,0xbc,0x27,0x02,0x68,0x44,0x04,0xd6,0x41,0x9f,0x03,0xd4,0x8b,0x08, +0x8c,0x77,0x85,0x34,0xa8,0xdf,0x48,0x72,0xb6,0xbc,0x2a,0x89,0xe7,0x48,0x92,0x90,0x8f,0x9f,0x5a,0x02, +0xe1,0x01,0xa2,0xdd,0xe0,0x72,0xde,0x45,0x24,0x0c,0xd5,0x51,0x72,0x08,0xdd,0x06,0x62,0xa6,0x8d,0xc4, +0x22,0xaa,0x6d,0xf7,0xfe,0x18,0x6d,0xf7,0x80,0xf0,0x80,0x94,0xd3,0x3d,0x98,0x2d,0x0d,0x1a,0x62,0x82, +0x0c,0xf1,0x90,0x34,0xd3,0xef,0xf2,0xe8,0x48,0x4c,0x8f,0x49,0x0e,0x32,0x51,0xec,0xa6,0x87,0xf0,0xc1, +0x6f,0x11,0x06,0xe6,0x70,0x73,0xff,0x5b,0xef,0x3b,0xcc,0x4d,0x8f,0x06,0x37,0xe6,0x62,0xcc,0xfd,0x26, +0x3a,0xcb,0x14,0xa2,0x63,0xe4,0x00,0xba,0xe9,0x93,0x14,0xce,0x27,0x40,0x33,0xe6,0xd0,0xb8,0xd8,0x94, +0x90,0x7a,0xa6,0x2c,0xf5,0xde,0x05,0x0b,0xd2,0x0c,0xab,0x67,0x04,0xa2,0x2f,0x80,0xbb,0x69,0x13,0xd7, +0x89,0x99,0x75,0x9d,0x2e,0x2a,0x8c,0x7f,0xea,0x50,0xe8,0xca,0x31,0xa9,0x94,0xf8,0xc1,0x3e,0x83,0xbc, +0xc0,0x3e,0x02,0x55,0xc0,0x37,0x9c,0x6d,0x32,0x31,0xd3,0xdd,0x94,0x6f,0x93,0x49,0xcc,0xe5,0xa7,0xb0, +0xcc,0x85,0xfe,0x87,0x06,0x88,0x17,0xf6,0x44,0x81,0x2d,0x8f,0x06,0xc9,0x36,0x63,0x89,0x20,0xf3,0x98, +0x36,0x4e,0x7a,0x3b,0x98,0x8b,0xef,0xd0,0x48,0x10,0x0c,0xe8,0xd7,0x2f,0xc2,0xbb,0xae,0x5a,0xb4,0xcc, +0x87,0x64,0x43,0x39,0x92,0xb5,0x84,0x46,0x4b,0x78,0x90,0x4e,0xd4,0x76,0x4b,0xa1,0x12,0x31,0x44,0xa3, +0xc1,0x9f,0x9e,0x50,0x13,0x21,0x83,0x0b,0xda,0x8f,0xb1,0x0b,0x8e,0x42,0x0e,0x07,0xc1,0x33,0x6b,0xdc, +0x8a,0x0d,0x2c,0x05,0x80,0x7f,0x8c,0xbe,0x8b,0xb4,0x45,0x22,0xd0,0x42,0x6e,0x7f,0x46,0x27,0xf8,0xbd, +0x19,0x2d,0x6c,0x30,0xe8,0x40,0xc0,0x83,0x8d,0x0d,0x38,0x84,0x81,0xaa,0x6c,0x7c,0x02,0xf4,0xa8,0xd9, +0x89,0x1e,0x2f,0x68,0x46,0xb6,0x96,0x01,0x76,0x5c,0x97,0x23,0xe3,0x5e,0x37,0x8f,0x41,0x64,0x1a,0xd6, +0x05,0xee,0xd9,0x25,0x61,0x90,0x2e,0x5f,0x9f,0x2a,0x3c,0xab,0x9e,0xf0,0x02,0x92,0x56,0xe1,0x66,0xa7, +0x86,0x06,0x1c,0xc1,0x80,0xa7,0xa1,0x61,0xdd,0xd0,0x0f,0x1b,0x7f,0xa8,0xf7,0xec,0x47,0xf0,0x5e,0x7a, +0x2b,0xea,0xd5,0xd4,0x34,0x0e,0x66,0xca,0x4b,0xb2,0x77,0x8e,0x5c,0xc7,0x48,0x4b,0xb5,0x40,0x95,0xe4, +0x46,0x0a,0x0e,0xf1,0x93,0xba,0x96,0x48,0x54,0xd5,0x00,0x99,0xfb,0xb2,0x04,0x06,0xa9,0xed,0xc5,0xf8, +0x33,0x80,0xe1,0x7e,0xa2,0x26,0xb8,0x08,0x21,0x0f,0x14,0x16,0x4d,0x8a,0xa7,0x9a,0x97,0x5a,0xa0,0x3d, +0x48,0x9c,0x7d,0x97,0x3b,0xf9,0x29,0xdf,0xd7,0xc0,0x0b,0xb4,0x15,0x41,0x9e,0x5e,0x8d,0xd8,0x8c,0x67, +0x5f,0x81,0x0a,0xca,0x39,0x3d,0x08,0x62,0xe6,0x8a,0x2b,0xa0,0x37,0x48,0xf3,0x7c,0x81,0x84,0xaa,0x38, +0x36,0x06,0xef,0x40,0xfe,0xac,0xc1,0xfc,0x44,0x9a,0x0d,0x3a,0x3e,0x0d,0x24,0x37,0xb3,0xf7,0x91,0x0a, +0x5c,0x30,0xcd,0x7c,0xc1,0x8d,0x22,0x20,0xf2,0xad,0x86,0xe0,0x82,0x2e,0x11,0xf2,0x65,0x9e,0x85,0x48, +0xaf,0x26,0x5c,0x31,0x9e,0x4f,0xa6,0xce,0xa7,0x63,0xd5,0x1b,0x20,0xf6,0x93,0x20,0x42,0xc1,0x74,0xc8, +0x24,0xd1,0xad,0x0e,0x4a,0x45,0xd2,0x21,0xd7,0x0f,0xb9,0x79,0xaa,0x52,0x93,0x17,0xb2,0xa1,0xc6,0x65, +0x08,0x72,0x1a,0x32,0xa2,0x2d,0x60,0xa6,0x49,0xe7,0x53,0xa2,0x63,0x3b,0xb8,0x81,0x53,0x4d,0xf0,0x7b, +0x50,0x40,0xef,0x59,0xaf,0x26,0x68,0xea,0x51,0x06,0x7a,0x9f,0x0a,0x55,0xb4,0xb7,0xd7,0x61,0xdd,0xd6, +0x8a,0xa9,0xc4,0x90,0x68,0x51,0x78,0x09,0xd4,0xb5,0x9a,0xef,0x2b,0xb2,0xd6,0x1a,0xe4,0x65,0x00,0xae, +0x89,0x2e,0x17,0xe7,0x53,0xd2,0x6f,0x52,0x94,0xce,0x04,0xa5,0x13,0x23,0x10,0xf3,0x28,0x89,0xc2,0xb5, +0x44,0xfb,0xef,0x62,0x6a,0x70,0x48,0x59,0x85,0xb5,0x04,0xd1,0x60,0x82,0x57,0x04,0x55,0x56,0x86,0x25, +0xb6,0xf5,0xe0,0xed,0xbb,0x79,0xe8,0x97,0xb7,0x2e,0xe6,0x40,0xa2,0xee,0xe3,0x08,0xab,0xa8,0x31,0x86, +0x60,0xd7,0x18,0x0f,0x21,0xe9,0xc5,0x1b,0xcd,0x60,0x8c,0x30,0xb3,0x5e,0xfd,0xce,0xee,0xdb,0xc6,0x03, +0x82,0x82,0xb2,0xce,0xf0,0xdb,0x17,0x4b,0xdb,0x4e,0x7d,0xb2,0xab,0xb0,0x9e,0x55,0x80,0x12,0xb8,0x80, +0x5f,0xfc,0x42,0x37,0x0d,0x54,0x62,0x93,0x40,0x3e,0x36,0xb9,0x3f,0x89,0x61,0xa0,0x03,0x3e,0x9d,0xc0, +0x13,0x62,0x09,0xae,0x96,0xa3,0x19,0x8d,0xd9,0xc3,0xf1,0xca,0xc3,0x35,0x6f,0x9e,0xf4,0x3d,0x9f,0xf4, +0xbf,0x23,0xcc,0xe4,0x7d,0xdd,0x35,0x6d,0xd5,0x23,0x63,0x37,0x9f,0xb6,0xd7,0x38,0xf1,0x20,0x63,0x8a, +0x23,0x12,0x22,0xaa,0x35,0x22,0xb9,0x00,0x27,0x07,0x32,0xc1,0xf9,0x26,0xd5,0x54,0x39,0x40,0x97,0xba, +0x67,0xa3,0x24,0x03,0x7b,0xd2,0xf0,0xa4,0x62,0x41,0xe5,0x1b,0xe0,0x0a,0x13,0x0f,0xf9,0x3c,0xa8,0x7b, +0x14,0x2d,0x4e,0x86,0x08,0x6e,0xf6,0xe0,0xbe,0x1c,0xa0,0xa5,0x6e,0x19,0x43,0x3a,0x3c,0xba,0xeb,0x30, +0x1f,0x4c,0xec,0xfb,0xe4,0x0d,0x08,0x1e,0xd4,0xff,0x30,0x4c,0xd4,0x86,0x59,0xb9,0x41,0x59,0xdb,0xbb, +0xcf,0x8a,0x44,0xd0,0x29,0xfe,0xdb,0x33,0xba,0x77,0x49,0xd9,0xb1,0xf1,0x0f,0x89,0x2f,0xc9,0x0d,0xc8, +0xb6,0x87,0xc7,0x0d,0xa5,0x27,0x68,0x85,0xd6,0xb5,0x65,0x4f,0x65,0x37,0x7a,0x23,0xa4,0x75,0xd7,0xd0, +0x71,0xf9,0x38,0xd0,0x91,0x75,0x83,0xe5,0x40,0x4b,0xcf,0xe3,0x6b,0xca,0x81,0x35,0xe5,0xc0,0x9a,0xca, +0x78,0x29,0xab,0xd6,0x40,0x27,0x5f,0xda,0xf8,0x26,0xe8,0x7f,0xcd,0xfa,0x0e,0xe2,0x32,0x20,0x63,0xf8, +0xe9,0x8b,0x1f,0xc4,0x91,0x91,0xb5,0x47,0x6a,0xd7,0xf0,0x66,0x35,0x83,0xb3,0x69,0x3d,0xe4,0xe5,0xfc, +0x33,0x4e,0x3e,0x27,0xaf,0xb2,0x94,0x78,0x4f,0x77,0x5c,0xf2,0xfe,0x7e,0xfb,0x9e,0x42,0x99,0x04,0x36, +0xae,0xfc,0x25,0xf1,0x1f,0x09,0xa2,0x09,0xf4,0x24,0x1a,0x51,0x4f,0x22,0x39,0xd9,0x51,0x8e,0x33,0xad, +0xc7,0x4a,0xa3,0xf0,0x12,0x7c,0xd1,0x09,0xfa,0x7f,0x88,0x15,0xa4,0xbe,0xfa,0xca,0xf9,0x8b,0x41,0xfc, +0x31,0xc1,0xf0,0x43,0xbf,0x40,0xad,0x25,0x36,0xaf,0x81,0xe9,0x40,0x1e,0x22,0xa2,0x6f,0x50,0x6a,0x03, +0x47,0x3f,0xb9,0x12,0x61,0xb4,0x13,0xe1,0x9e,0x84,0xf5,0xd4,0xbb,0xc7,0xa4,0x3d,0xb4,0x21,0x4a,0x57, +0xe5,0x0a,0x71,0xfa,0x27,0xfd,0xda,0xb7,0xed,0x3b,0x97,0x15,0x03,0xc2,0x65,0xf6,0xb1,0x9a,0x1d,0x5b, +0xec,0x56,0x5d,0x64,0x04,0xfe,0x8f,0x1a,0xfa,0xe4,0xc1,0x7c,0xc1,0x63,0xcb,0xa8,0x7a,0x92,0x2d,0xe3, +0xff,0xa8,0x49,0x94,0x10,0xd4,0xf9,0xf5,0xcb,0x05,0x0a,0x40,0x2b,0x57,0xbc,0x59,0x5b,0x4b,0x8f,0xb2, +0x2a,0x05,0xa7,0xcb,0xc4,0x13,0xf7,0x2e,0xa8,0x94,0xc9,0x20,0x5d,0xd2,0xb3,0x80,0x95,0x63,0xff,0xd7, +0x2f,0x19,0x08,0xec,0xeb,0x89,0x3b,0x71,0x1c,0xe6,0x32,0x80,0x59,0x01,0xed,0x0b,0x29,0x68,0xc6,0x19, +0x08,0x2a,0xc2,0xf0,0x56,0x48,0x55,0xfc,0xc4,0x5c,0xf3,0x1e,0x45,0xb9,0x93,0x9b,0x99,0x2c,0xfd,0x64, +0xff,0x13,0x9e,0xcd,0xd0,0x61,0x6d,0x33,0x14,0x52,0x3d,0xf6,0x0c,0x6c,0xd2,0xf8,0xf5,0xeb,0xdd,0xe4, +0xd7,0x2f,0xdf,0x15,0x39,0x81,0x96,0x52,0xc8,0x04,0x0c,0x6b,0xac,0x6f,0xf7,0x71,0x47,0x4e,0x43,0xf7, +0xf4,0xe4,0xc3,0x07,0xfc,0x44,0x6a,0x8e,0xd0,0x61,0x9c,0x14,0x3a,0x2c,0xc6,0x35,0xb6,0x31,0xdc,0xc2, +0x01,0x9c,0x92,0x7f,0x04,0xbd,0xdd,0x63,0x68,0x78,0xee,0xbd,0x86,0xea,0x7b,0x74,0x63,0x07,0x39,0x42, +0x16,0xef,0xae,0xeb,0x99,0xf6,0xb4,0xf6,0x6d,0xe0,0x3f,0xa7,0x83,0xc7,0x2f,0xd2,0xf3,0x2d,0xe8,0xe1, +0x04,0x8f,0xef,0xdb,0x66,0x33,0x6e,0x92,0x7a,0x1f,0xd0,0x8c,0xef,0xd2,0xc6,0xad,0x91,0x80,0x35,0x07, +0xce,0x7a,0xdf,0x1f,0xde,0xc5,0x9a,0x9f,0xba,0x35,0xb3,0x9a,0x9c,0x91,0xdb,0x15,0xad,0x02,0x53,0x10, +0xa7,0xe8,0xe6,0xd7,0x2f,0x73,0x41,0x43,0x54,0x09,0x6d,0x85,0x24,0xd0,0xb8,0x69,0xf0,0x46,0x61,0x32, +0xd8,0xaf,0x0c,0xf3,0xf4,0xb3,0x8e,0x98,0xb2,0x8c,0xea,0xbb,0xdf,0x7d,0xd0,0x64,0x0f,0x39,0x34,0x2a, +0xfb,0x49,0x40,0x5f,0x72,0xc4,0x76,0x25,0x25,0x62,0x1a,0xf8,0x8e,0x6f,0xf3,0x29,0x25,0x0d,0xbb,0x5b, +0xf3,0xbf,0x00,0xdc,0xc1,0xb8,0x70,0x73,0x08,0xf4,0xfb,0x74,0x50,0x2f,0x0c,0x12,0x7c,0x0a,0x50,0x0f, +0xed,0x04,0x48,0xf6,0x0f,0xf4,0xc4,0x12,0xba,0x54,0x2e,0xa8,0x8f,0xc6,0xa9,0x34,0x63,0xf2,0x97,0x82, +0xfc,0xe5,0x56,0xfe,0x52,0xfc,0x0e,0xa4,0x0e,0x46,0xdb,0xbb,0x42,0x40,0xef,0x5a,0x0a,0x47,0x3f,0xf9, +0x24,0x40,0x80,0x57,0x30,0xdd,0xc9,0x7e,0x6d,0xc2,0xe5,0x46,0xaa,0x3a,0x91,0x5d,0x17,0x3e,0x7b,0x48, +0x3f,0xf2,0x61,0x56,0x11,0x3d,0x28,0x26,0x45,0x0d,0xa0,0x51,0xe0,0xe7,0x1f,0x3e,0x04,0xd3,0x3b,0x8f, +0x5c,0x30,0xa1,0xd9,0x44,0xe2,0xee,0x04,0x33,0x25,0x42,0xac,0x47,0x82,0x4f,0x5e,0x04,0x69,0x5c,0x1f, +0x29,0x36,0x8a,0x3f,0x61,0xb5,0xe1,0x32,0xa9,0x82,0x02,0x97,0x1e,0x81,0x0c,0xc5,0xe2,0x13,0x1c,0x0c, +0xae,0xa1,0x31,0xdb,0xb8,0x42,0x38,0x92,0x63,0xda,0xba,0x12,0x6f,0xf8,0xbf,0xb5,0x7c,0xc8,0x9d,0xf1, +0x25,0xc6,0xc1,0x43,0x50,0x58,0x2c,0x90,0x82,0x78,0x35,0x12,0x0f,0x08,0x45,0x93,0xe4,0xbe,0x85,0xde, +0x3d,0xce,0x0c,0xc8,0xff,0x4f,0xae,0x5d,0x58,0x84,0xdc,0xc5,0x4b,0xfb,0x33,0x35,0x1b,0xe7,0x83,0x15, +0x80,0xe7,0x3c,0x0c,0xd8,0x7a,0x47,0x2e,0xc7,0x24,0xed,0x44,0xd9,0x69,0xce,0x55,0xb0,0x00,0x6a,0x39, +0x8c,0x3e,0x89,0xc9,0x62,0xd3,0xa0,0xb3,0x24,0xd8,0xc6,0x31,0xce,0x8c,0x9a,0x7a,0xb4,0x91,0xa1,0xd2, +0x0b,0x74,0xfa,0xfa,0x95,0x9d,0xef,0x01,0xb0,0x76,0x8a,0xc1,0x0c,0xa8,0xe0,0xdd,0x02,0x70,0xb4,0xe5, +0x6f,0xf0,0xed,0x55,0x8f,0x36,0xc1,0x82,0xc1,0x5f,0xcd,0x09,0x18,0x12,0x58,0x57,0xa0,0x69,0x70,0x0f, +0xbb,0x30,0xbd,0xd3,0xe4,0x0c,0xd8,0xd1,0x7b,0xba,0xe3,0xe8,0x5a,0x32,0x15,0x43,0xaf,0x1c,0x26,0x40, +0xba,0xa9,0x0f,0x9f,0x70,0xa6,0xa4,0x8f,0xc8,0x5c,0x53,0xc2,0x73,0x2c,0x19,0x14,0x7d,0x10,0x5d,0xff, +0xa0,0x8d,0x64,0x49,0x2f,0x37,0xd9,0x4c,0xa1,0xe6,0xb0,0x66,0x66,0x35,0x9e,0x55,0x0f,0x44,0x3c,0x7a, +0x59,0x73,0xc1,0x1b,0xd2,0xb1,0x6a,0x85,0x8c,0x83,0x1a,0x39,0xf4,0x67,0x32,0xf9,0xeb,0xfb,0x26,0xd4, +0x3f,0xc6,0xdb,0x2a,0x7a,0x03,0xf8,0xfb,0x6f,0xea,0xf7,0xac,0x33,0xb6,0x24,0x87,0xb7,0x9b,0xa5,0xfb, +0xd7,0x66,0x37,0x86,0x87,0xdb,0xe4,0xdf,0x4c,0x98,0x7e,0x9c,0x0f,0xfb,0x0f,0x50,0x99,0xc6,0x9f,0xac, +0x2a,0xf2,0x88,0xf9,0x42,0x85,0x34,0x4e,0xa8,0x0b,0x04,0xec,0xda,0xe6,0x44,0xf7,0x3f,0xc0,0xcb,0x77, +0x85,0xd4,0x13,0xb0,0x07,0x57,0xc4,0x3f,0x24,0x1f,0x11,0x1d,0x60,0xc4,0x63,0x6e,0x3a,0xb7,0x1a,0x72, +0xb2,0xc1,0x80,0xec,0x91,0x27,0xbf,0x04,0x4d,0xf9,0x91,0x92,0x8f,0xa9,0x66,0x4b,0xc5,0xdc,0x00,0x55, +0x28,0xa6,0xb3,0x27,0x0a,0xf1,0xc0,0x27,0x7f,0x83,0xe4,0x09,0xa6,0x2e,0x6d,0x3b,0x46,0x1f,0x53,0x8a, +0x72,0xcb,0xd9,0xd0,0xdd,0xaa,0xe7,0xbf,0x3c,0x65,0xf7,0xd1,0x57,0xad,0xb4,0x8f,0xd1,0xaa,0x40,0xb9, +0xc0,0x62,0xd5,0xf2,0x11,0x9a,0x66,0x78,0xc2,0x7d,0x33,0xbe,0xe1,0x81,0xbf,0x03,0x8b,0x53,0x32,0xad, +0x00,0x1a,0xfa,0x08,0xe3,0x36,0xb3,0x38,0x0a,0x52,0x46,0xd9,0x63,0x36,0x34,0x04,0xd2,0x92,0xf8,0x07, +0x36,0x00,0x1f,0xfd,0xfe,0x84,0xd1,0x3e,0x84,0x03,0xf3,0xfb,0x04,0x80,0xda,0x23,0xa9,0x47,0xe1,0x69, +0x44,0x87,0xa7,0xf7,0x29,0x32,0xc3,0xa0,0x00,0x4a,0x84,0x45,0x76,0x2f,0x73,0x95,0x82,0x48,0xf5,0x5d, +0xa2,0xfe,0xec,0x5b,0x6c,0xf6,0x0b,0x92,0x3f,0x38,0xb9,0xfa,0xdc,0xa6,0xc1,0x3c,0x48,0x55,0xf1,0x3d, +0x4a,0xd9,0xd0,0xeb,0x34,0x76,0xfc,0xf4,0x84,0x22,0xd0,0xcc,0xd2,0x3c,0x13,0x14,0x5f,0xd0,0x85,0x14, +0x83,0x90,0x54,0x58,0x11,0x94,0x57,0x9b,0xaf,0x13,0x9a,0x69,0x3d,0x2d,0x6a,0xfb,0xaa,0x61,0xd8,0x27, +0x89,0x9b,0xc3,0xf6,0x08,0xb9,0x4d,0x44,0x47,0x33,0x69,0x05,0x8a,0xae,0xe9,0x43,0x8a,0xca,0xe2,0xa4, +0x01,0x78,0xf7,0x33,0x5e,0x37,0x4d,0xfe,0x21,0x29,0x84,0x08,0x7d,0x69,0xdd,0xf4,0x9f,0x69,0xa6,0xdd, +0x4b,0x7d,0x89,0x61,0x20,0x11,0x41,0x8f,0xf2,0x4f,0x11,0xa8,0x03,0x75,0x68,0xf0,0x7d,0x87,0x3c,0x6b, +0xac,0x84,0xf8,0xcd,0x63,0x7f,0xf8,0x5b,0x7c,0x16,0xe0,0x89,0x6c,0x1c,0x3c,0x2a,0x88,0xbf,0xc5,0x67, +0x9f,0xc7,0xf0,0x77,0xec,0x57,0x60,0x77,0x0c,0x75,0x27,0x19,0xac,0x9c,0x71,0x5a,0x2c,0x34,0x15,0x0c, +0x99,0xaa,0x99,0xa6,0x71,0x57,0x65,0x24,0xa0,0xf8,0x30,0x03,0xe6,0x77,0x1d,0x78,0x1d,0x22,0x51,0x53, +0x3e,0x7d,0x64,0x7f,0xd8,0x86,0x95,0x4c,0x28,0xb2,0x79,0xb6,0x17,0xda,0xaf,0x90,0x37,0x28,0xd0,0xc8, +0x0a,0x6f,0x58,0x50,0xf0,0x28,0x6e,0xf7,0x27,0x12,0x41,0x03,0xb7,0xd1,0x10,0x2a,0xa0,0x82,0xb0,0x08, +0xf1,0x68,0x63,0x96,0xbc,0xc5,0x5e,0x5a,0x5a,0x7c,0x60,0x0f,0x02,0xcf,0xdb,0xf1,0xfc,0xa0,0x1f,0x27, +0x89,0x1e,0xde,0x2a,0xb4,0xb8,0x96,0xf8,0x96,0x58,0x9b,0xdf,0x3a,0x33,0x84,0x2e,0x64,0x7c,0xf2,0xaa, +0x89,0x04,0xd8,0x9a,0xdf,0x13,0xc0,0xe6,0xb1,0xf3,0xa7,0x60,0xe3,0x11,0x1a,0x15,0x35,0xdf,0x05,0xdb, +0xc3,0x00,0x85,0x43,0xc2,0x91,0x95,0xf3,0xb7,0x20,0xbc,0x94,0xe8,0xcf,0xa0,0xe6,0xbc,0x6f,0xc6,0x77, +0xd6,0xa2,0x3f,0xc4,0x73,0x09,0x47,0x61,0xe6,0x31,0x1f,0xb6,0x47,0x81,0x14,0x5e,0xda,0xab,0xe1,0x8e, +0xfd,0xb6,0xb0,0xb2,0x90,0xb1,0x47,0x82,0x10,0x23,0x73,0x84,0xfe,0xf8,0x10,0x8d,0x5a,0x29,0x72,0x18, +0x6f,0x3b,0x20,0xf8,0x0c,0xda,0xf4,0x4c,0xac,0x51,0x10,0x05,0x48,0xdf,0x4f,0xb8,0x59,0xe8,0x5b,0xeb, +0x14,0x1d,0x90,0x66,0x82,0x58,0x27,0x85,0x1b,0x8d,0xb8,0xb1,0xe5,0x0e,0x8c,0x9e,0x87,0xed,0x54,0xa3, +0xdf,0x88,0x3f,0x59,0xb2,0xde,0x70,0x18,0xcc,0xa2,0x14,0x6a,0xe9,0xb2,0x39,0x1d,0x0b,0x0a,0xb2,0xbf, +0xb9,0x18,0x70,0x97,0xf6,0xc3,0xf3,0x68,0x8f,0x3b,0x1c,0x97,0xc7,0xeb,0x80,0xcc,0x48,0xb2,0x06,0x45, +0x68,0x68,0x14,0x55,0x26,0x98,0x30,0xbf,0x7e,0xd9,0x20,0x66,0x3e,0xa9,0x9f,0xde,0x81,0x4d,0x60,0x82, +0x8e,0x46,0x36,0x45,0x15,0x37,0x48,0x54,0x4f,0x45,0x4d,0xdf,0xf5,0x07,0x02,0x2b,0xd2,0xc0,0xbf,0x50, +0x24,0x81,0x38,0x7e,0x62,0xbb,0x0d,0x20,0x50,0xd4,0x1a,0x46,0x91,0xdd,0x78,0x7e,0x50,0x8e,0x5c,0x1d, +0x75,0x15,0x30,0x2b,0x6c,0x32,0x61,0x71,0x97,0x0f,0xe7,0x25,0x18,0xf7,0xe7,0x88,0xbe,0x84,0xe4,0xa2, +0xfe,0x50,0xef,0xdb,0xfc,0xd6,0xe2,0x6c,0xcf,0x54,0x3d,0x2e,0x76,0x7e,0xfd,0xe2,0x5b,0x57,0xec,0x82, +0xba,0x94,0xef,0xe6,0x44,0xa5,0x04,0xe6,0x3d,0x69,0xc0,0xbf,0x9f,0xf4,0xaa,0x83,0x41,0x30,0x00,0x58, +0x2a,0x85,0xca,0x0a,0x7e,0x0c,0xfc,0x75,0xe4,0xae,0x0e,0xa4,0x23,0x1a,0x44,0xf2,0xfe,0xdc,0xd7,0x18, +0x13,0xdd,0xf7,0x37,0x8b,0x4b,0x89,0x41,0x35,0xd0,0x83,0x01,0x6e,0xc3,0x80,0x60,0xf8,0x14,0x30,0x90, +0x02,0xa5,0x90,0x70,0x95,0x0a,0x02,0x45,0x28,0x0e,0x0a,0x59,0x02,0x70,0x18,0xe6,0x55,0xf7,0x70,0x59, +0x5f,0xe8,0xee,0x08,0xc6,0xa4,0xef,0x53,0xc2,0xe0,0x64,0x82,0x7b,0xfa,0x33,0x97,0x6c,0x53,0x12,0xe9, +0xd1,0x49,0xf9,0x8b,0xc4,0x45,0xde,0xee,0xc2,0xca,0xf8,0xf0,0x01,0xff,0x66,0x2b,0x16,0xd8,0xed,0xe3, +0xd8,0x9f,0x1e,0x23,0xb5,0xdd,0x01,0x21,0x7b,0x47,0xf6,0x1d,0x00,0x03,0xb5,0xac,0x94,0xcd,0xe0,0xc2, +0x15,0xf7,0xe8,0x37,0x66,0xb1,0xd8,0xeb,0x31,0xdb,0x3c,0xc5,0x61,0x61,0xa6,0x6a,0x14,0x17,0xb0,0x02, +0x95,0xc4,0x1a,0x7e,0xf8,0x8e,0x2a,0xa2,0xc1,0x5b,0x54,0xc9,0x74,0x07,0xad,0x8f,0xcc,0x55,0x15,0x7b, +0xb0,0x85,0x10,0xc1,0xa8,0x31,0xac,0x00,0xfa,0x8d,0x0f,0x0a,0x68,0x94,0x16,0x88,0x9e,0x00,0xad,0xba, +0x3e,0x17,0x6d,0x27,0x5c,0x0f,0x48,0x40,0x5d,0x19,0x9f,0x7c,0x59,0xb1,0x18,0x37,0xd0,0x7a,0x09,0x09, +0x2a,0x69,0xa2,0x12,0xa8,0x29,0xf3,0x9b,0x1a,0x5e,0xcf,0xdf,0x6b,0xa1,0xa1,0xa8,0xdf,0xb9,0x4f,0xb5, +0x2b,0xa6,0x64,0xdb,0x66,0x1e,0x64,0x14,0xc5,0x84,0xfa,0x5d,0xca,0x91,0xca,0xe2,0x94,0xac,0x6f,0x31, +0xef,0x81,0x78,0x80,0xdc,0xc7,0x1f,0x3e,0x38,0xc8,0x8b,0x11,0xc2,0x5d,0x92,0xab,0xb8,0xb1,0x56,0x93, +0x5f,0xe0,0xce,0x8a,0x3f,0x02,0xb2,0x2a,0xec,0xb4,0xd4,0x33,0x05,0xcc,0x10,0x95,0xd8,0x38,0x23,0x3e, +0xa3,0x84,0x77,0x88,0x3d,0x40,0x1d,0xc6,0xda,0xd1,0xac,0xa8,0x35,0xf3,0xdb,0x98,0x66,0x01,0x63,0xb9, +0x4c,0x58,0x35,0xf4,0x98,0x7e,0xa7,0xa6,0xa4,0x4d,0x5b,0x24,0x86,0x9a,0x01,0x6a,0x80,0x69,0x78,0x24, +0x4f,0xd2,0x2e,0x60,0xca,0xdf,0xfd,0x17,0x4d,0xe0,0xe2,0x0b,0x5a,0xa1,0x5f,0x40,0x32,0x2a,0xba,0xf0, +0xf2,0x9f,0x54,0xda,0xf0,0xad,0xe2,0x5f,0xef,0xf0,0x05,0x39,0x28,0xb1,0x4c,0xba,0xeb,0x4f,0x24,0xb6, +0x9a,0x92,0xe8,0x4a,0xa5,0x92,0xd8,0x3d,0x18,0x14,0xfa,0xb7,0x04,0xc5,0xf3,0xba,0x89,0xef,0x29,0xaf, +0xa6,0x26,0x05,0x67,0xc7,0xd0,0x0d,0xf6,0x9b,0x47,0x6a,0xf4,0xfc,0xfd,0x06,0xcc,0x4b,0xa5,0x57,0x13, +0xe4,0xd9,0x74,0x74,0x0c,0xf3,0x4f,0xa4,0xe9,0x9f,0xaa,0xfa,0xa9,0x57,0x4d,0x9c,0x50,0x2e,0x6b,0x3c, +0x55,0x4c,0x11,0xb6,0x78,0x95,0x26,0x50,0xe3,0x1a,0xe5,0xef,0x06,0x2c,0x3c,0x3d,0x3d,0x85,0xdb,0x71, +0xc7,0x64,0x4d,0x26,0xd2,0x88,0xfa,0xaa,0xf7,0x44,0x2c,0xc9,0xd3,0x31,0x98,0xc9,0xd2,0xa5,0xe3,0x07, +0x69,0x47,0xaf,0x31,0x6f,0x06,0xdf,0x13,0x62,0x6e,0xcf,0xd3,0x5e,0xda,0xd0,0x6b,0x1e,0xdf,0x71,0xf8, +0xff,0x99,0x7b,0xd7,0xed,0xb6,0x8d,0x6c,0x5d,0xf4,0xff,0x7e,0x0a,0x11,0xed,0x56,0x00,0x13,0xa4,0x28, +0x39,0x4e,0x77,0x40,0xc1,0xdc,0x8e,0x1c,0xc7,0xee,0xb6,0x63,0xb7,0xad,0x5c,0xba,0x29,0x26,0x03,0x22, +0x21,0x09,0x09,0x05,0x30,0x00,0x68,0xc9,0x11,0xd9,0x6f,0x76,0xc6,0x79,0xa4,0xf3,0x0a,0x67,0x7e,0x73, +0x56,0x15,0x0a,0x17,0xca,0x59,0xbd,0xf6,0x1a,0xe7,0x64,0xc4,0x22,0x2e,0x85,0xba,0x5f,0xe6,0xf5,0x9b, +0x7e,0xc6,0xd7,0x22,0x7b,0xf3,0x23,0xbe,0xc1,0x3e,0xed,0x17,0x7c,0xc9,0x4e,0x76,0xf4,0xc5,0x3a,0xc6, +0x8c,0x5d,0xc6,0xe1,0x1a,0x3a,0xea,0xf7,0xbc,0xa7,0xfa,0x73,0xbe,0xbd,0x8a,0x8a,0x37,0x37,0xa9,0x56, +0x39,0xf9,0x17,0x71,0x38,0xb7,0xd2,0xac,0xe2,0xf0,0x42,0xd9,0x74,0x4b,0x5d,0xc0,0x76,0xb1,0x44,0x0d, +0x50,0x07,0xc3,0xa3,0xe1,0xa1,0x43,0xfb,0xba,0x65,0xb5,0x61,0x59,0x4a,0x40,0x5e,0x0b,0x3a,0x25,0x35, +0x92,0x5a,0xe2,0x0a,0x3e,0xc4,0xe1,0xc1,0x4f,0xd3,0xb3,0xe2,0x6c,0xfd,0xfc,0xeb,0xe7,0xcf,0xcf,0x6e, +0x9f,0x8e,0x66,0xfd,0x4d,0xe3,0xfe,0xc1,0xc1,0xa5,0xff,0x11,0xe9,0x06,0xd7,0xc5,0xe0,0xc0,0xbf,0xa6, +0xcb,0x81,0x3b,0x8d,0x06,0xbf,0xcf,0x3c,0x7a,0x73,0xbb,0xa3,0xb8,0xb2,0x2e,0x98,0xde,0x8e,0xb9,0x6c, +0x45,0xee,0x49,0xdf,0x85,0x77,0xbf,0xb0,0x99,0x5c,0x70,0x45,0x84,0x25,0x2d,0x9a,0x32,0x5f,0xc3,0x5a, +0x8e,0xb8,0x0a,0x5f,0xd3,0xd2,0x7e,0x99,0x31,0xfd,0xd1,0xa1,0x61,0x4a,0xe2,0x4a,0x25,0x4d,0x2d,0xa9, +0xa9,0xa1,0xaa,0xa3,0x5e,0x64,0x25,0xf1,0xa4,0x96,0x3a,0x88,0x8f,0x47,0x13,0x5c,0x4d,0xe3,0x3e,0xab, +0xa3,0xa4,0xb8,0x59,0x20,0xcf,0x66,0x5b,0x1f,0x83,0xf6,0xbe,0x8c,0xe6,0xbf,0xd6,0xf2,0x34,0xfa,0x20, +0xd1,0x19,0xf3,0xa7,0x56,0xc5,0x69,0xc7,0xb6,0x0c,0x3b,0x40,0x42,0x7f,0x90,0x51,0x12,0xd1,0x67,0x09, +0xb6,0x69,0x7e,0xd5,0x55,0x4b,0x43,0x5a,0x21,0x5d,0x4c,0xad,0x21,0xaa,0xb7,0x2b,0x1d,0x97,0x68,0xea, +0xe6,0x2a,0xf2,0xb8,0xee,0x84,0x62,0xbb,0x42,0x18,0xfb,0xff,0x14,0xa3,0xed,0x51,0xc6,0x3c,0x4d,0x3b, +0x7a,0xb3,0x91,0x73,0x12,0x77,0xeb,0xe6,0x28,0x07,0xd6,0xdb,0xef,0xca,0x21,0xfe,0xcd,0x1d,0x81,0xd9, +0x8c,0xee,0x4d,0x32,0x00,0x43,0x1a,0xff,0xd6,0xd1,0xb7,0xd6,0x68,0x10,0xff,0xdd,0x8f,0xfb,0x2e,0x0f, +0x55,0x30,0xaa,0xfa,0xb5,0x5e,0xd1,0xf4,0x49,0x48,0xbb,0x4e,0x7a,0x5c,0x4e,0xa6,0x3c,0x78,0xe9,0x6c, +0x46,0xac,0x22,0xb2,0x4f,0x17,0x3b,0x9b,0x69,0x06,0x86,0xce,0xd1,0xd6,0x18,0xca,0xe0,0x07,0x11,0x51, +0x41,0x59,0x5e,0x06,0x58,0xda,0xf4,0xeb,0x63,0x9f,0xa4,0x9e,0xc3,0x2d,0x5f,0x6d,0x7d,0x43,0x04,0x84, +0xb2,0xac,0xd4,0x8d,0x55,0x28,0xda,0x64,0x99,0x94,0x11,0x91,0x63,0x7a,0x92,0xcf,0x4d,0x18,0xb5,0x84, +0x87,0xb4,0xd3,0x9b,0xc7,0xba,0xed,0x4b,0x2d,0x18,0x73,0xce,0xb3,0x0c,0xda,0xf3,0x8a,0x7e,0x8e,0x58, +0xdc,0x19,0xd5,0x32,0x2b,0x54,0x66,0xc4,0xbf,0xf9,0x2d,0x82,0x5b,0x74,0xd4,0x16,0x55,0x1a,0x89,0x56, +0x9a,0x88,0x1b,0x2a,0x9e,0xcf,0x0e,0xba,0xe3,0x81,0x2e,0x06,0x03,0x6f,0x5c,0x1c,0xaf,0xc7,0x85,0x70, +0x82,0x4a,0xc3,0x1f,0xd7,0x8a,0x12,0x9a,0xb6,0x14,0x59,0x54,0x1a,0x46,0x50,0x86,0xe7,0xec,0x2c,0xe2, +0x47,0x4a,0x9e,0xb4,0xe4,0xe3,0x4e,0x88,0xe1,0xb7,0xcb,0x28,0x49,0x95,0x1c,0x38,0x47,0xc9,0x49,0x58, +0x67,0x2d,0x60,0x31,0x3c,0x71,0xd9,0xe0,0xad,0x77,0x48,0x47,0x5e,0xba,0xbf,0x5f,0x4f,0x90,0x7a,0x93, +0x14,0x83,0x1a,0xf0,0xbb,0x56,0xa6,0xfc,0x1a,0x24,0x24,0xd5,0xc0,0xb2,0x18,0x82,0xdc,0x84,0xb2,0x0e, +0x0c,0x85,0x87,0x1a,0x71,0x9a,0xdc,0xd6,0xfb,0xf9,0x96,0xf8,0x43,0xb9,0x45,0x04,0xca,0x6d,0x8c,0xb8, +0x97,0xab,0xb8,0xcf,0x42,0xa0,0x1c,0xcf,0xaf,0xe9,0x14,0x36,0x56,0x14,0x07,0x67,0xcf,0x68,0xf7,0x83, +0x21,0x45,0xc2,0xe1,0x5e,0x3f,0x06,0x20,0x05,0xf9,0x1c,0xb2,0xa7,0x75,0xd3,0x23,0x0d,0x8b,0x3b,0xcd, +0x6c,0x71,0x82,0x47,0x55,0xaf,0x06,0xa7,0x63,0xd5,0x57,0xfe,0x58,0x96,0xa1,0x2c,0xf2,0xd1,0x4e,0x59, +0xbb,0xf6,0xbd,0x1e,0xbc,0x35,0x62,0x96,0xb9,0x8b,0xbb,0x1a,0x3e,0xf9,0x96,0xc6,0x31,0x4f,0xe6,0xdd, +0xfb,0x5a,0xdd,0x11,0xcc,0xad,0x7c,0xba,0xd8,0xc3,0xcb,0x98,0x18,0x85,0x60,0xb8,0x7b,0x94,0x57,0xf4, +0xad,0x1b,0x0f,0x2c,0x1d,0x63,0xec,0x71,0xb5,0xac,0xd1,0x69,0x97,0xe3,0x6b,0xc3,0xec,0x9e,0xdb,0x83, +0xfd,0xcb,0x54,0xe6,0xeb,0x9e,0xa4,0x9f,0xb1,0xdb,0x42,0xac,0xfd,0x73,0x58,0xc9,0x9e,0xa3,0x4e,0x1e, +0x33,0x65,0x73,0xb3,0xa3,0x39,0xd6,0xa2,0x85,0xe4,0xbc,0xb4,0x57,0xb1,0x6f,0xfb,0xb0,0x69,0x1b,0xc9, +0xcd,0x46,0x9f,0x9d,0x29,0xbc,0xbc,0x56,0xaa,0xb2,0x96,0x9e,0xa2,0x5d,0xd9,0xb1,0x35,0xd5,0x8d,0xa8, +0xd0,0xd8,0xa0,0xfa,0xc8,0xfa,0xbe,0x53,0x07,0x4e,0x31,0x41,0x6b,0x41,0xb2,0x43,0x4d,0x35,0xa6,0xfa, +0xe9,0x64,0x1d,0x4f,0xab,0x96,0xcf,0x2a,0x06,0x38,0xd0,0x29,0x68,0xb2,0x1a,0xd3,0xa0,0x5a,0xb1,0x29, +0xcf,0x07,0x23,0x0f,0xee,0xaa,0x52,0x6c,0x66,0xee,0xc7,0xd8,0x77,0xe8,0x24,0x77,0xaa,0xb9,0x7c,0x1d, +0xd3,0x31,0xee,0xb5,0x8e,0xa7,0x8a,0xa9,0x22,0xe6,0x97,0x99,0x09,0x8c,0x83,0x18,0xfb,0x19,0x13,0xef, +0xe4,0x38,0xe5,0xce,0x17,0x5b,0x29,0x62,0xbb,0x13,0x1f,0x3f,0xe8,0x61,0xea,0x2a,0x62,0x7a,0x9b,0xbc, +0x3a,0xcb,0xaf,0x3b,0x3e,0x10,0xeb,0x54,0x26,0x13,0x2b,0x03,0x1e,0x9f,0xa6,0xdc,0xf5,0x7d,0x3d,0x4c, +0xfd,0x0b,0xce,0xdf,0x6a,0xcc,0x87,0x58,0x3c,0x68,0xae,0xa3,0x5f,0xe3,0x06,0xed,0x60,0x5b,0x09,0xda, +0x42,0x15,0xb3,0x58,0xa8,0x85,0x6a,0x53,0xa1,0x86,0x56,0x16,0xf9,0x69,0xdb,0x81,0x28,0x9e,0x10,0x9d, +0x10,0xc4,0x1e,0x9d,0x13,0x5a,0x63,0x0a,0xa2,0x3d,0xa5,0x19,0x95,0xb6,0x4b,0xb5,0x8e,0x64,0xa9,0x78, +0x39,0x19,0x1c,0x06,0x96,0x7b,0x1e,0x6c,0x5c,0x7d,0x2e,0xac,0x51,0xdb,0xca,0xe6,0xbf,0xaf,0xed,0x58, +0x94,0xf6,0xd9,0x8c,0x40,0x7e,0x4c,0x2b,0x8a,0xfa,0x39,0x66,0x11,0x03,0xab,0x01,0x4c,0x07,0xaa,0x34, +0x21,0xf5,0x31,0x4d,0x1e,0xea,0xa2,0x56,0xb5,0x6c,0x3d,0x72,0xcb,0xd1,0x84,0xce,0x87,0x5e,0x6a,0x79, +0x9b,0xf4,0x4a,0x76,0xc6,0x80,0x9d,0x68,0x4e,0x03,0x5c,0x18,0x93,0xf1,0xd8,0xf6,0xc7,0x48,0x9a,0xf4, +0x4b,0x25,0xd0,0x97,0x53,0x10,0xba,0x58,0x11,0x97,0x98,0x19,0x65,0xb5,0x27,0x3a,0x4e,0x58,0x44,0x9e, +0x85,0x28,0x2d,0xa2,0x53,0x05,0x32,0x65,0x19,0x23,0xe2,0x4d,0x8a,0xba,0x91,0x7a,0xc5,0xd9,0x7d,0xfa, +0x03,0xcd,0x6e,0x5a,0x46,0x98,0x4c,0x3a,0xae,0x93,0x45,0x70,0xe8,0xb3,0x18,0xb2,0x73,0xfa,0x53,0xdf, +0xb0,0x15,0x78,0x73,0x12,0x88,0xa0,0x88,0x4f,0x3e,0xf8,0xea,0xc6,0x61,0xda,0x14,0x52,0x5a,0x3a,0xf4, +0x50,0x93,0xa0,0xe6,0x2c,0xf5,0x8f,0x3c,0xdb,0xc4,0xda,0x5a,0xaa,0x8a,0xf6,0x12,0xf2,0x04,0x96,0x88, +0xa2,0xcc,0x6f,0xe5,0xe0,0x79,0x95,0xad,0x75,0x6c,0xff,0xf0,0x91,0x2f,0xa6,0xd6,0x7e,0x82,0x13,0xe7, +0x26,0x78,0x46,0xec,0x0e,0x8c,0x1a,0xfc,0x62,0xbd,0x82,0x6f,0x75,0xb0,0x88,0x89,0x00,0xe8,0xd8,0x88, +0xde,0x7f,0xbc,0x3e,0xcf,0x96,0x72,0x7c,0x5f,0xa4,0x53,0xb9,0x1d,0x26,0x25,0x62,0xa3,0x66,0x39,0x4d, +0xb0,0xb8,0xf5,0xcc,0x33,0xd2,0x24,0xe7,0x2b,0xa1,0x57,0xf6,0xc4,0x19,0x6d,0x4f,0x18,0x97,0x3d,0xdd, +0x21,0x7b,0xbc,0x36,0xf6,0x50,0x97,0xbd,0x77,0xf1,0xe5,0xd7,0xb7,0x2b,0xb5,0xef,0xcb,0xf1,0xa8,0xca, +0x76,0x6c,0xae,0xb4,0x3e,0x20,0xb4,0x47,0x9a,0x13,0xc3,0xe9,0x97,0x90,0xf6,0xcd,0x5a,0xae,0xc1,0x22, +0xb3,0x3b,0xb7,0x39,0x13,0x4b,0x24,0x56,0xee,0x94,0x23,0xf8,0x73,0x98,0x29,0x60,0x3b,0xab,0x9b,0xf1, +0x5d,0xd1,0x7a,0xad,0x6c,0xaa,0x83,0x2f,0x31,0x19,0xb4,0x8f,0x5c,0x4b,0x24,0x46,0xbb,0x3b,0xce,0x35, +0x98,0x41,0x5e,0xed,0xef,0x7f,0x29,0x3f,0x6c,0x96,0x7e,0xa5,0xe7,0x42,0x8a,0x0c,0x7a,0xa0,0x47,0x5c, +0x64,0x5c,0x2b,0x8c,0xc6,0x3c,0x78,0x80,0xdd,0xf3,0xc5,0xfe,0xfe,0x2b,0x28,0xd4,0xd9,0x65,0xfc,0x85, +0xff,0x46,0x14,0xf8,0x87,0x2a,0x5f,0x77,0x1d,0x7e,0x54,0x96,0x64,0x34,0xc7,0xc4,0x50,0x00,0xfe,0x28, +0x9c,0xe8,0xcb,0x10,0x85,0xb1,0x80,0x06,0x94,0x9d,0xe5,0xd2,0xf4,0xd5,0xc7,0x97,0x0b,0xd8,0x10,0xd4, +0x6a,0x12,0x0d,0x69,0xde,0x84,0xa1,0xd1,0x59,0x28,0x1f,0x0c,0xb8,0x6d,0x6c,0xb5,0x98,0x61,0xc5,0x44, +0xe2,0xaa,0x23,0xab,0xfd,0xfd,0x97,0xb4,0x83,0xb1,0xcd,0xe2,0x27,0xf2,0xb9,0x63,0xa9,0xd2,0xd1,0x4c, +0xbf,0xff,0xbb,0x9a,0xe7,0xc4,0x9c,0x74,0x7b,0x5d,0xf1,0x8e,0x8a,0x1a,0x72,0xe3,0x1e,0xc1,0x19,0xf9, +0xb4,0x9e,0xf2,0x04,0xd2,0x6c,0x71,0x1d,0x2f,0x77,0xbc,0xf9,0x64,0x69,0x26,0x25,0x5a,0x43,0x55,0xa5, +0xf2,0x4e,0x87,0xbf,0x15,0x44,0x67,0xf7,0xbe,0x23,0x06,0x91,0x26,0x21,0x84,0x3b,0xbd,0xb7,0x34,0xae, +0x6f,0xb5,0x98,0x5b,0x0d,0x06,0x0f,0x2a,0x4d,0x19,0x48,0x9f,0x2a,0x89,0x4c,0x25,0xb7,0xde,0x65,0x8b, +0x2e,0xdb,0xae,0x5b,0xc8,0xd8,0x58,0xd2,0xf9,0x64,0xe1,0xd0,0xc1,0x53,0x84,0x85,0x39,0xce,0x6e,0x62, +0xff,0x34,0x86,0xbb,0x71,0xd1,0x4c,0x48,0x9b,0xe8,0x0f,0x30,0x57,0x78,0x2f,0xe6,0x69,0x4b,0x63,0xd2, +0x03,0x33,0xc7,0x25,0x3b,0xdd,0xfd,0xc9,0xe9,0x17,0x2c,0xc5,0x21,0x72,0x98,0x77,0x68,0x68,0x83,0x44, +0x81,0xe0,0x3b,0x70,0xd9,0xba,0x36,0xde,0xba,0xfb,0xfb,0x38,0x95,0x2b,0xa3,0x5a,0x22,0xbd,0x4a,0x74, +0xc5,0xdc,0xb3,0xdc,0x68,0xaa,0x3e,0x5c,0xb5,0x3d,0xdc,0xe6,0xdc,0x7b,0x22,0xae,0xb9,0x24,0xaa,0xf6, +0x02,0xda,0xbe,0xe5,0xc7,0x3b,0xf0,0x18,0x3f,0x60,0x7c,0x5a,0xbe,0x0d,0x68,0xad,0x11,0xc8,0xc0,0xaf, +0xc1,0xb4,0xba,0xa0,0x43,0xfc,0xc1,0x21,0x1c,0x2b,0x1b,0x62,0x7c,0x6c,0x93,0x95,0x48,0xd0,0x4d,0x2b, +0x3f,0x7e,0x70,0xdc,0x2c,0x12,0x47,0x83,0xbd,0x27,0x27,0xb4,0x55,0xce,0xaf,0xe2,0x57,0xca,0x92,0xdc, +0x68,0xa7,0x4b,0x2d,0x50,0x9b,0x11,0xd9,0xc1,0x69,0x89,0x21,0x10,0xa1,0x4f,0x58,0x51,0x04,0x96,0x38, +0x37,0xb7,0x89,0xa8,0xe9,0x0f,0x2c,0x3b,0xb7,0x5e,0x27,0x15,0x01,0xfd,0xa2,0xe9,0x71,0xa6,0x03,0x28, +0x39,0xde,0xb8,0xea,0xc4,0x5e,0x2f,0xae,0xc4,0x5a,0xa9,0xed,0xbb,0xa4,0xfa,0xab,0xac,0x59,0x47,0xdf, +0xe7,0x59,0x5a,0x86,0x38,0xe4,0x2c,0x0d,0x40,0xd6,0x24,0x1a,0x62,0xbd,0x93,0x6e,0x1c,0xd6,0x54,0x1b, +0x9a,0x01,0x73,0xe4,0x64,0x18,0xd1,0x58,0xbc,0x60,0xd7,0x8e,0x69,0x4a,0x64,0x03,0xed,0xa4,0x2d,0x30, +0x00,0x45,0x2e,0x11,0x23,0x81,0xef,0xdb,0x36,0x3c,0x75,0x7f,0x13,0xc8,0x38,0x8b,0x6c,0x9d,0xcf,0xe3, +0x97,0x90,0x75,0x0d,0x4a,0xfb,0x4e,0xe4,0xd1,0xfa,0x3c,0xe4,0x4d,0x54,0xd4,0x23,0xb4,0x97,0x0e,0x53, +0x62,0xc2,0xde,0x27,0xe7,0x4b,0xda,0x4b,0x59,0xc4,0x9a,0x32,0x9b,0x21,0x89,0x07,0x87,0x66,0x5c,0x26, +0x87,0xc1,0xc0,0x72,0xf3,0x2a,0x3a,0xb5,0x3a,0x9f,0x74,0x05,0x51,0x8c,0x95,0xed,0x10,0x52,0x8a,0x1b, +0x0e,0x35,0xce,0xea,0xcf,0xf5,0x7f,0x27,0x7b,0xd7,0xca,0x9f,0x88,0x79,0x05,0x10,0x8d,0x3b,0x6f,0x47, +0x71,0xcb,0x1d,0xc5,0x69,0x3e,0x30,0xcb,0xaf,0xd9,0x98,0x6e,0xd2,0x9c,0x22,0x8b,0xa4,0x60,0x8c,0x6b, +0xa6,0xa1,0x27,0x0e,0x83,0xd6,0x48,0x4a,0xeb,0xda,0xfa,0xa6,0x96,0x81,0xfd,0x75,0x1c,0x94,0xcd,0xdb, +0xa4,0x78,0x66,0x3d,0x80,0xe6,0xa1,0x7a,0x02,0x22,0x9f,0x2a,0xf0,0x35,0x66,0x74,0xd7,0xd7,0x56,0xe9, +0x8d,0x6a,0xda,0xcd,0x9e,0x5b,0xcd,0xce,0xdd,0x76,0xc3,0x69,0x69,0xf5,0x4b,0xdf,0x7a,0x23,0x2a,0x2e, +0x35,0xc9,0x61,0x21,0x12,0x83,0x94,0xd3,0x93,0x1b,0x36,0x0c,0x70,0x30,0xd1,0xe4,0x24,0xa6,0x7a,0x3a, +0x85,0xf9,0x4b,0x34,0x13,0x31,0x7d,0x42,0x8b,0xd8,0xcd,0xf1,0x83,0x6b,0x8f,0xed,0xee,0x6c,0x54,0x06, +0x6b,0xc1,0xef,0xef,0xff,0x71,0xe7,0x61,0x9a,0xfc,0x75,0xd8,0x85,0x06,0xae,0x42,0x65,0x62,0x32,0xf2, +0x2b,0x0e,0x8a,0x96,0x95,0xe3,0x8c,0x4b,0x22,0xe2,0x4b,0xd0,0xd8,0x7d,0xa6,0x27,0x87,0x8c,0xff,0x68, +0x34,0x4e,0xbb,0x90,0x13,0x42,0xf4,0x29,0x7b,0x68,0xf0,0xfa,0xa1,0x9e,0x48,0x36,0x1b,0x98,0x9e,0xc0, +0x61,0xa9,0x1a,0x61,0xd6,0x1a,0xd0,0x71,0xf1,0x73,0xbf,0x5f,0x89,0x27,0x59,0x8e,0x57,0x81,0x14,0x60, +0xa3,0x55,0x6e,0xbf,0xe3,0x52,0x98,0x08,0xaf,0xe5,0x4e,0xb6,0xd9,0x44,0xc6,0x56,0x5e,0x7d,0x31,0x36, +0xfb,0x57,0xcd,0x26,0xc3,0x5f,0x2b,0x15,0x22,0xcc,0x42,0xe1,0x1b,0xfc,0x95,0x5f,0xcc,0xc4,0x85,0xa6, +0x55,0x46,0x47,0x21,0xd4,0x95,0x2a,0x17,0xcd,0x76,0x8f,0xb6,0x86,0xdc,0xbf,0xbf,0x7e,0xf4,0xf0,0x82, +0xde,0xff,0x00,0x37,0x76,0xfc,0xb0,0x9c,0x6b,0x1e,0x5e,0xd0,0xce,0xbf,0x4e,0x13,0x3a,0xb5,0x5e,0x3e, +0xc3,0xab,0xda,0x3d,0xa7,0x81,0x03,0x6c,0x78,0xcf,0x99,0x2d,0xa5,0xd2,0x02,0x18,0x6b,0x62,0xc6,0x5d, +0x86,0x73,0x1c,0xab,0xfb,0xfb,0x4b,0xf8,0x48,0x85,0xe1,0x57,0xb8,0x62,0x25,0x4a,0xa1,0xfb,0x69,0x45, +0x04,0x4f,0xb8,0xa4,0x3f,0xa2,0x8b,0xa2,0x53,0x79,0xe5,0xf3,0xb3,0x76,0x03,0x4d,0x4f,0xd6,0x10,0x26, +0x2c,0xb6,0x40,0x26,0xcc,0x93,0xc3,0xfa,0xa8,0xd9,0x6b,0xc1,0xe2,0xcb,0x95,0xb3,0x43,0x0f,0xcc,0xb5, +0x4a,0xd7,0x21,0xc2,0x08,0xe0,0x3e,0x51,0x03,0x51,0x68,0xe6,0x08,0xb5,0x77,0x5a,0x71,0xfb,0x19,0xf3, +0xf4,0xa0,0xa1,0xb1,0x76,0x2a,0xd5,0xb0,0x3d,0x49,0x3f,0xee,0x70,0x24,0x07,0x83,0x59,0xb0,0x59,0x54, +0x5c,0x09,0x3a,0x85,0x4f,0x2b,0x8d,0xd8,0x91,0x4d,0xdc,0x8b,0x99,0x27,0x8e,0x41,0xbd,0x14,0x0e,0xca, +0x94,0x0f,0x3b,0x91,0x2a,0x46,0x0e,0x6e,0xc5,0xea,0xb4,0x2f,0xba,0x8d,0xf8,0xaf,0x55,0x0d,0x98,0xb8, +0xaf,0x54,0x06,0x90,0x5a,0xd1,0x94,0x60,0x6b,0xb8,0x6b,0x26,0xf7,0x88,0x3f,0xec,0x65,0xf2,0x28,0x0b, +0xe1,0x54,0x16,0xc1,0xfe,0xa4,0xda,0x6a,0x72,0xe1,0x0d,0x1a,0x93,0x19,0x8e,0xee,0xf4,0xe7,0x0a,0x6e, +0xdd,0xd2,0x8e,0x4b,0x38,0xfe,0x7e,0x50,0x5e,0xfe,0x7e,0x61,0x39,0xae,0x17,0xb3,0xa0,0xf0,0xa7,0xc4, +0x22,0x5d,0x87,0xe0,0x0b,0x40,0xf6,0x97,0x93,0xcb,0xe0,0xa3,0x7b,0xe9,0xaf,0xfc,0x98,0x33,0xf7,0x6f, +0xc3,0x74,0x92,0x41,0xe3,0x3c,0x89,0x83,0x2b,0x78,0xbb,0x4d,0xa6,0xb3,0x20,0x0a,0xae,0xf9,0x8c,0xdc, +0xdf,0x4f,0xdd,0x6b,0xff,0x56,0x52,0x26,0x7c,0x62,0x2e,0xc3,0x8f,0xee,0xad,0xbf,0x60,0x65,0xba,0x8f, +0x4e,0xc5,0xab,0x79,0x45,0x02,0xb2,0xd3,0x39,0x2d,0x83,0xe5,0x74,0xce,0x1d,0x79,0x3b,0x5d,0xd0,0x15, +0x76,0xbd,0x6b,0x75,0x75,0xa1,0xd5,0xc3,0x98,0xc7,0x19,0x7c,0x56,0xf8,0x42,0x86,0x6b,0x19,0x32,0xf8, +0xc7,0x6d,0x33,0xbb,0x5b,0xc9,0x6e,0x29,0x5d,0x7f,0x4d,0x77,0x94,0xcf,0x38,0x63,0x31,0x31,0xb5,0x61, +0x0a,0x47,0xb9,0x35,0xed,0xa4,0xec,0x23,0xb7,0xeb,0x6b,0xca,0x3d,0x9b,0xc4,0x31,0xf5,0xec,0x85,0x17, +0xac,0xf0,0xec,0xc9,0xe0,0x10,0xa2,0x97,0xe9,0x12,0x15,0x8c,0xf0,0x73,0x01,0x7b,0x48,0x5e,0xef,0xb7, +0x68,0x69,0x08,0x2f,0xa4,0x5b,0x25,0x78,0x77,0xaf,0x7c,0x9d,0xb5,0x17,0xdc,0xd2,0x08,0x4e,0x54,0x05, +0x22,0xea,0xa3,0xb5,0x17,0x68,0x1a,0x95,0x6e,0x6b,0xdb,0xfa,0x6d,0x6d,0x0b,0x96,0xd9,0x59,0xcd,0xc3, +0x2c,0x3c,0x19,0x02,0xdd,0x17,0x3e,0xe2,0x53,0x71,0x29,0xa2,0xd1,0x9b,0xe1,0x20,0xd9,0x6c,0xac,0x57, +0xa0,0x17,0x69,0x0e,0x67,0xb0,0xf4,0xa7,0x79,0x6c,0xf9,0x4e,0x36,0x30,0xa1,0xb6,0x54,0x1f,0x31,0x27, +0xee,0x4e,0x13,0x6b,0x54,0x26,0x9d,0x70,0x1e,0x4e,0x2d,0x56,0xb7,0x62,0x4f,0xc3,0x1e,0x14,0xb2,0x70, +0x2b,0xa7,0xd3,0xf6,0x17,0xac,0x03,0x80,0x95,0x78,0xd5,0x0c,0x5b,0xab,0xe4,0xc1,0x52,0x5d,0x54,0xba, +0x92,0x50,0x30,0x3d,0xb6,0x33,0x5a,0x5d,0x89,0x11,0xea,0xd7,0x9b,0x5a,0xa8,0xa6,0x7a,0x54,0x01,0x22, +0xdc,0x89,0x8c,0xa7,0xe3,0x65,0x66,0xf6,0x38,0xa4,0x16,0x4b,0x30,0x2b,0xad,0x66,0x03,0x90,0x3b,0x3f, +0x65,0x3b,0x18,0x40,0x18,0xa4,0xb4,0x96,0xa4,0x9b,0xf3,0xb0,0xdf,0x2f,0xc6,0xf9,0x31,0x16,0x5d,0xad, +0xc0,0x5c,0x65,0xc2,0x42,0x2b,0x5d,0xd5,0x6b,0xb7,0x80,0x1b,0x2b,0x17,0xcf,0x57,0x74,0x62,0x2a,0x2d, +0xfe,0xc8,0x2f,0x06,0x87,0xc6,0xa1,0xe1,0x8e,0x4f,0xc6,0x80,0xc6,0x01,0x54,0xc4,0xb4,0x18,0x1c,0x49, +0x76,0x13,0x5a,0x77,0x81,0xe3,0x6c,0x2d,0x11,0xbd,0x61,0x22,0x52,0xbf,0x38,0xce,0xe1,0x44,0xa8,0xb3, +0x2c,0xc4,0xcc,0x0c,0x75,0xbb,0x05,0xd0,0x55,0x05,0xdd,0x24,0x0f,0x17,0x2c,0xc9,0x9e,0x1b,0x1b,0x1b, +0xad,0xa6,0xa3,0xda,0xd5,0xe1,0x32,0xb4,0x58,0xcb,0xec,0x90,0x4f,0xb0,0x5d,0xc6,0xd5,0x4d,0x14,0x36, +0xb7,0x12,0x7f,0x29,0xdf,0xf0,0x56,0xa2,0x00,0x33,0x9c,0x91,0x83,0x1d,0x64,0x7f,0x1f,0xe8,0x20,0x58, +0x47,0xd7,0xe1,0x2f,0xb4,0xa0,0x68,0xd0,0x69,0xec,0xd1,0xff,0xe9,0x62,0x78,0xfa,0xf4,0x1b,0x28,0xfb, +0x61,0xd4,0x76,0x1e,0x7e,0xd5,0x0f,0x45,0x90,0x78,0x4d,0x13,0xb1,0xa6,0xa1,0xd8,0x6c,0x86,0x87,0xfe, +0x4d,0xb5,0xfa,0x78,0x3d,0xd3,0x04,0xfa,0x25,0x84,0xce,0xfe,0x05,0xdb,0xeb,0x2c,0xbd,0xf1,0x15,0x4d, +0xa6,0x1b,0x6d,0x89,0x85,0xd5,0x3a,0xbd,0x22,0xf6,0xf0,0x8a,0x46,0x84,0xf7,0x81,0xfd,0xfd,0xb9,0x8c, +0x22,0x3c,0x92,0xe9,0x8b,0x79,0x5d,0x48,0x21,0x39,0xb9,0xaf,0x78,0xb4,0xc2,0xde,0x1b,0x6f,0xbc,0xa2, +0xb1,0xb8,0xd0,0x00,0x13,0xb0,0xd8,0x8b,0x20,0xb4,0x28,0xd8,0xba,0x84,0x7b,0x71,0xae,0x4d,0x00,0x50, +0x99,0xaf,0xc2,0x73,0x6f,0x0b,0x24,0x03,0x2a,0xb9,0xb7,0x42,0x61,0xd4,0xe7,0x83,0x01,0xf0,0x7e,0x2e, +0x75,0x72,0x76,0x32,0x58,0xf4,0xc3,0x2b,0x1c,0xcc,0xa8,0xee,0xc2,0xd4,0x88,0x4a,0x4b,0x55,0x69,0x2b, +0xda,0x46,0x3f,0xa0,0x63,0xad,0xed,0x6c,0xf1,0x64,0x24,0x7c,0xc5,0x15,0x76,0x9e,0x4b,0x6a,0x19,0x6d, +0xcd,0xfc,0xd7,0xc5,0x4f,0xf8,0x0f,0x91,0xa2,0xd1,0xd1,0x3b,0xfe,0x40,0xdb,0xcb,0x07,0x6f,0xab,0xf7, +0x8c,0xb5,0xff,0x81,0x0f,0x17,0x6c,0xd2,0x1f,0xcc,0x20,0x52,0xdd,0xfa,0x66,0x7c,0x0f,0x71,0xf4,0x08, +0xe1,0xf0,0x3e,0xcb,0x4b,0xca,0x45,0xcf,0x0e,0xd5,0x30,0xff,0x97,0xf0,0xda,0xf3,0x2f,0x0d,0x0c,0x5a, +0x32,0xc9,0xdd,0xc8,0x0b,0x22,0xe6,0x31,0x6f,0xfc,0x53,0xff,0xc4,0xff,0xda,0xff,0xd5,0x7f,0xef,0x7f, +0xeb,0x3f,0xf3,0x7f,0xf1,0x9f,0xfa,0xbf,0xf9,0xaf,0xfc,0x17,0xfe,0x73,0xff,0x8d,0xff,0xd6,0x7f,0xe7, +0xbf,0xf6,0x5f,0xfa,0x3f,0x84,0x4e,0x91,0xfc,0xfe,0xfb,0x32,0x76,0xfa,0x87,0x0f,0xa1,0x3b,0x82,0xbc, +0xcc,0x7f,0x60,0x5b,0x23,0x7c,0x45,0xe3,0xf2,0x33,0xfd,0xfb,0x3d,0x24,0x8e,0xd8,0xff,0x91,0xff,0x7e, +0xc7,0x7f,0xbf,0xef,0xd6,0xc7,0xf3,0xa6,0x44,0x35,0xfc,0x0d,0xc6,0x17,0xfe,0x68,0xeb,0x7f,0x43,0x44, +0x4f,0xd3,0xdc,0xe0,0x9f,0x98,0x7b,0xff,0x08,0xff,0x39,0x5c,0x65,0x2b,0xff,0x6f,0xf8,0x85,0xf1,0xc2, +0xdf,0xf5,0xc5,0xbf,0xe8,0x42,0xec,0x1c,0xe2,0xa6,0xd6,0xff,0x13,0xd8,0x34,0xb0,0x99,0x81,0x21,0x55, +0xc5,0xd3,0x19,0x7c,0x1e,0xec,0x80,0xa5,0x0e,0xba,0x11,0x2f,0x36,0x02,0x69,0x4e,0x17,0x11,0x40,0xe9, +0x37,0x70,0x7e,0xbb,0xa0,0x56,0x17,0x7c,0xc5,0xfe,0x18,0x2a,0x70,0x75,0xb1,0x59,0xc0,0xf6,0x7b,0xa3, +0xb9,0x8a,0x8d,0x98,0xfc,0x6f,0x92,0xe2,0x3a,0x5a,0x6d,0x96,0x59,0xb6,0xda,0x5c,0xaf,0x97,0x65,0xb2, +0x5a,0xc6,0x1b,0x6a,0x5f,0xba,0xd1,0x60,0x9a,0x1b,0x1d,0x1d,0x73,0x53,0xcc,0xe9,0xc5,0xc2,0x81,0xa5, +0x87,0x33,0x3d,0x3b,0xbb,0x3d,0x1a,0x9d,0x9d,0x95,0x67,0x67,0xf9,0xd9,0x59,0x7a,0x76,0x76,0x31,0x73, +0x60,0xf4,0xe1,0xb8,0x93,0xe0,0x8c,0xfe,0x1b,0x6e,0x28,0xc5,0xcd,0x60,0xb6,0x99,0xfe,0x74,0x36,0x1a, +0x50,0xe2,0x68,0x34,0xf3,0xfa,0x0e,0xcc,0x3f,0x9c,0xb3,0xb3,0xa9,0xd3,0x4f,0xe3,0xbe,0xf3,0xd0,0x75, +0xfa,0x39,0xfd,0x7a,0xf4,0x91,0x7e,0x32,0x7d,0xf8,0xd3,0x83,0x4d,0xef,0xdf,0xb3,0x49,0xe8,0xe9,0x47, +0x93,0xe0,0x33,0xb7,0xca,0xf6,0x27,0xfc,0x7e,0x36,0xf3,0x1e,0x7a,0x9f,0x6d,0xce,0x9c,0xe6,0x8b,0x33, +0x07,0x6f,0xce,0x9c,0x8d,0xce,0xda,0xdb,0xe8,0x7c,0xce,0xce,0xa8,0x8a,0x19,0x95,0x1f,0x58,0xc5,0x9e, +0x9d,0xb9,0xae,0xfb,0x5f,0xcf,0xde,0xdb,0x34,0xdf,0xb8,0x1e,0x35,0x78,0x36,0xdb,0x38,0xfd,0x04,0x59, +0x3f,0xf4,0x36,0x43,0x4a,0x78,0x86,0xe2,0x61,0xda,0x82,0x79,0x29,0x22,0x5c,0x17,0x95,0xa1,0x9e,0x70, +0x2e,0x61,0x44,0x54,0x7b,0xe3,0xfc,0x24,0x55,0xed,0x73,0xee,0x3f,0xa9,0x9c,0x67,0x9e,0x2e,0x8a,0x72, +0x55,0x09,0x1e,0xa8,0xef,0xd7,0x9d,0xdf,0x3f,0xf4,0xd5,0x2f,0x30,0x65,0xba,0x53,0xb8,0xd3,0x27,0xfd, +0x7f,0xa3,0xb6,0xb8,0xf3,0xaa,0xe4,0xf3,0x7a,0xf2,0xd0,0x24,0xa7,0xaa,0xcc,0x3e,0xa3,0xe6,0x3f,0x9c, +0xd4,0xfa,0x93,0x6b,0x71,0x51,0xfb,0x28,0x8b,0x3d,0x98,0xde,0x34,0x4a,0x45,0x87,0x3f,0x70,0xc4,0x02, +0xe7,0xe5,0xb3,0xa0,0xf6,0xf6,0x4f,0x7a,0x40,0xe8,0xfd,0xc9,0xab,0xa7,0xef,0xdf,0xd7,0x5f,0x53,0xcb, +0xad,0x04,0xb4,0xb3,0xd7,0x5f,0xab,0x77,0x9b,0xe9,0xc3,0x19,0xde,0x3f,0x3d,0x3d,0x7d,0x17,0x34,0x0a, +0x4f,0xa8,0x4a,0x6f,0xdf,0x7f,0xfd,0xdd,0xb3,0x37,0xcd,0x37,0xa8,0xec,0xc9,0x8b,0x97,0xaf,0x1a,0x35, +0x0a,0x5c,0x9e,0xfa,0xcc,0xf5,0x6d,0x60,0x9f,0xb1,0x49,0xcb,0x2b,0xfc,0x1b,0xe0,0xc6,0x1b,0xb8,0x0c, +0xbf,0xb0,0xc9,0x2e,0x06,0x0c,0x88,0x21,0x13,0x49,0xf7,0x15,0xf0,0x3b,0x36,0xd9,0x62,0x41,0xa3,0x38, +0xed,0xd3,0x12,0xf0,0xdc,0xb3,0xb3,0xc5,0x43,0x2f,0xdd,0x58,0x33,0x5a,0xbd,0xd1,0x0f,0x28,0x41,0x9f, +0xa6,0x4a,0xd5,0xb5,0x3c,0x6f,0x9c,0x84,0xda,0x03,0x93,0x86,0x46,0x83,0xb1,0x5a,0x4a,0x74,0xc7,0x03, +0x95,0x26,0x8d,0xe3,0x45,0xc1,0xf6,0x8c,0xb7,0x65,0xb3,0x85,0x9c,0xa1,0x8c,0x76,0x50,0x55,0x2d,0xfe, +0x6d,0x73,0x49,0x2d,0x93,0x76,0x55,0xcd,0x6c,0xb4,0x84,0xee,0x68,0xed,0x2e,0xbc,0x09,0x37,0xc0,0xae, +0x9c,0x3b,0x09,0xa7,0x3f,0x51,0x0b,0x1e,0xa8,0x6a,0xb2,0x51,0xd5,0x01,0xaa,0xc6,0x62,0x1c,0xb5,0x2f, +0x6d,0x34,0x0c,0xc8,0x46,0xe4,0x39,0xde,0x83,0x83,0x04,0x26,0x57,0x07,0x3f,0x5d,0x9d,0x2d,0x70,0x2d, +0x16,0x55,0x3f,0xdd,0xcd,0xfa,0x67,0x77,0x67,0xc5,0xc3,0xb3,0x69,0xca,0x74,0xcf,0xde,0xd9,0xcd,0x81, +0x58,0x51,0x51,0x86,0x7f,0x72,0xa7,0xd8,0x49,0xa8,0x7f,0xdc,0xb3,0x1b,0xfa,0x4b,0xb3,0x41,0x3d,0xa0, +0xec,0xd8,0xc0,0x6a,0x4a,0x8d,0x3b,0x80,0x6d,0x95,0xdd,0x74,0x5e,0x94,0xb4,0x26,0x17,0xd1,0xe0,0x62, +0x76,0x77,0xe8,0x7f,0xb1,0x95,0xfa,0x4f,0x36,0xaa,0x79,0xb4,0x42,0xb9,0xf2,0x98,0xc1,0xe7,0xf5,0x1d, +0xba,0x12,0x19,0x38,0xa3,0x5b,0xea,0xeb,0xc1,0x17,0x8f,0x1f,0x3f,0xfa,0xc2,0xf0,0x6e,0x30,0x8f,0x20, +0x0a,0x73,0x52,0x06,0xf9,0xf1,0x68,0x22,0x4a,0x9b,0x21,0x8c,0xe7,0x4e,0xae,0xa2,0xfc,0x04,0xf0,0x52, +0x79,0x9f,0xbf,0xf0,0x82,0xce,0x97,0x4f,0x9e,0x1c,0x8e,0x36,0x8f,0x1f,0x1f,0x7d,0xf9,0x85,0x7f,0x38, +0x3a,0x7a,0xb4,0x9f,0x6f,0x1e,0x7f,0xf1,0xe8,0x08,0xa6,0x40,0x37,0xd4,0x1a,0xaa,0x34,0xed,0x98,0xb7, +0x87,0x17,0x67,0xb7,0x7f,0xb9,0x98,0x6d,0x7e,0x1a,0x4c,0x68,0x04,0xe8,0xe7,0x81,0xda,0x4b,0xd5,0x9b, +0xc1,0xd9,0xfa,0x39,0xfd,0x87,0x9e,0x38,0xb8,0xf4,0x4f,0x77,0x19,0x96,0x4d,0x9c,0xb3,0x91,0xa0,0x4f, +0x3a,0xff,0xcf,0xff,0xfd,0x7f,0x39,0x41,0x45,0x27,0x12,0x99,0xd8,0xa7,0x5e,0x02,0x12,0xcf,0x5c,0x55, +0xed,0x29,0x20,0x5e,0x34,0x54,0x87,0x67,0x2c,0xe9,0xdc,0xc3,0x2f,0x3c,0xc8,0x7e,0x03,0x49,0xbe,0xf5, +0x4f,0x6a,0x3e,0xa0,0xaf,0x60,0x06,0xf4,0x75,0xbc,0x83,0x74,0xaf,0x89,0xdb,0x60,0xf3,0x68,0x24,0x73, +0xd0,0xec,0x1b,0x91,0x17,0x34,0xea,0x77,0x8b,0x24,0x0f,0x6c,0x49,0x8c,0x0f,0x39,0x4d,0xe0,0x48,0x74, +0x26,0xa2,0x56,0x59,0x30,0xac,0xc9,0x8f,0x7f,0x86,0xff,0x12,0xd2,0xe4,0x41,0x0d,0x16,0xac,0x7e,0xf7, +0xcf,0xe9,0x83,0x36,0x54,0xca,0xac,0x02,0x74,0x15,0xc1,0xf2,0xaf,0x54,0xdf,0xbf,0x87,0x77,0x9c,0x6f, +0xf0,0x4f,0x95,0x6a,0x52,0xef,0xd0,0xbf,0xa9,0x62,0x63,0x5f,0x15,0x5b,0x7a,0x36,0x36,0x65,0x4b,0x94, +0x5c,0xa9,0x9f,0xc7,0x10,0x9d,0x8b,0xae,0x99,0xa9,0xb0,0xb1,0x51,0x34,0xe3,0x38,0xdf,0x6e,0x4f,0xc3, +0x72,0xa8,0xd4,0x8c,0xb0,0x4e,0xfc,0x35,0x84,0xd0,0xf0,0xc7,0xd7,0xaf,0x6a,0x0a,0x39,0xe5,0xe7,0x00, +0xf7,0xb3,0xa6,0x0a,0x8c,0x81,0x59,0xe5,0x46,0x49,0xd9,0xb4,0xc4,0xa2,0x47,0x34,0x8c,0x03,0xf4,0xb5, +0xba,0x7a,0x65,0xeb,0xbf,0x0a,0x59,0x45,0x62,0x28,0xd4,0x0e,0xbb,0x13,0x10,0x26,0x93,0x76,0x59,0xc1, +0x03,0x7b,0x19,0xbc,0xd8,0xdf,0xff,0x32,0xb4,0x11,0x4c,0xf6,0xf7,0xf3,0x66,0x65,0x26,0xee,0x8b,0x30, +0xf7,0x9f,0x87,0x2f,0x9a,0x2f,0xfc,0x37,0x61,0xef,0x57,0xf7,0x05,0x0d,0x99,0xe4,0x44,0xdc,0xd3,0x0b, +0x83,0x0b,0x94,0xc4,0x37,0x0c,0x70,0x46,0x54,0x8c,0xc2,0x29,0x48,0x01,0x89,0x54,0xc3,0x72,0x9d,0xb4, +0x1f,0x01,0x85,0x5a,0x00,0x5e,0x4f,0x62,0xd8,0xcd,0x07,0x29,0xc4,0xf6,0xd1,0xfc,0x8a,0x53,0x21,0x43, +0xeb,0xd6,0x75,0xb2,0xb4,0x4a,0x4e,0xec,0xcc,0x29,0xcb,0xf8,0x59,0xdf,0x52,0x84,0x49,0xf7,0x74,0x9e, +0x6b,0x05,0x58,0x48,0xfb,0x9e,0xdf,0xeb,0xf4,0x18,0xc1,0x6b,0x07,0x36,0xfb,0xa7,0x9d,0xa2,0xcf,0x5d, +0x59,0xdb,0xc0,0x70,0x5a,0x3d,0x72,0x92,0x5d,0x8b,0x7a,0x04,0x6e,0xa8,0xbd,0x1d,0x80,0x8b,0x38,0xba, +0xd5,0x9c,0x6a,0x17,0x6a,0x34,0x76,0xe1,0x07,0xa5,0xbf,0x7a,0xb1,0x4b,0xf9,0x27,0x9f,0x42,0x57,0xd9, +0x5d,0xc5,0xe7,0xb5,0x2a,0xd2,0xbc,0x4b,0x16,0xe1,0x0f,0x7e,0xaf,0x91,0x1f,0xb2,0xda,0x6c,0xba,0x9e, +0xba,0x3f,0x34,0xab,0x89,0xb2,0x26,0xae,0x66,0x9a,0x87,0x2f,0x9f,0x75,0x4d,0x7a,0xc3,0xa3,0xde,0xc6, +0xb4,0x53,0x57,0x60,0x77,0x5d,0x7d,0xd8,0xd6,0x10,0xb2,0x7c,0x81,0xf6,0x2c,0x61,0x0c,0x6b,0x25,0x60, +0xcd,0x42,0x07,0xd9,0x21,0xb4,0x6e,0xea,0x81,0xf7,0xf7,0xdf,0x54,0x9a,0x8c,0x86,0x5e,0xb7,0xaa,0x52, +0x3a,0x21,0xba,0x3d,0x98,0xce,0xb6,0x5b,0x2f,0xf8,0x3f,0xd0,0x2a,0x29,0x6f,0xa7,0x4c,0xdd,0x34,0x54, +0x34,0x1b,0xed,0x67,0xd2,0x01,0xa6,0x72,0x98,0xfe,0x12,0x2a,0xe9,0xff,0x70,0x97,0x88,0xc5,0x66,0x67, +0xc7,0x88,0x9c,0x8c,0x45,0x23,0xd9,0x8e,0xfa,0xf9,0xb5,0x8a,0x69,0x15,0xf4,0x34,0x9b,0x29,0x57,0xc0, +0xb2,0x63,0x22,0xc5,0x1e,0xef,0xac,0x59,0x98,0xa8,0x4d,0xf5,0x3f,0x2b,0x41,0x71,0xa3,0x3c,0x60,0x7e, +0x25,0x3a,0x08,0xbb,0xd7,0xed,0xa4,0xeb,0x88,0xfd,0x54,0x4f,0x59,0x9f,0xef,0x54,0xdc,0x07,0xac,0x42, +0xa7,0xf7,0x2d,0x35,0x71,0xac,0x4d,0x32,0x9b,0x47,0x8d,0x86,0xd6,0x20,0x16,0x54,0x3b,0x5b,0xed,0xc8, +0x7c,0x6c,0x7c,0x21,0x94,0x48,0x6f,0x9c,0x1a,0x07,0x2b,0x28,0x04,0xd2,0xda,0xe6,0xad,0x84,0x38,0x95, +0x9c,0x5a,0x9b,0x01,0x99,0xe9,0xc2,0x14,0x7a,0xb3,0x87,0x2c,0xd3,0x82,0xff,0xf2,0x5c,0xaa,0x7f,0xfe, +0xc6,0x38,0x83,0xee,0x32,0x3c,0x00,0xa9,0xf0,0x0e,0x0d,0x7f,0x8b,0x3f,0x62,0x7e,0x60,0xed,0x6d,0xcd, +0x3e,0x64,0x63,0xc8,0xfa,0x76,0xd6,0xde,0xc7,0x0c,0x4c,0xa9,0x73,0x1c,0x21,0xa6,0xc3,0x67,0x4e,0xff, +0x87,0xbe,0xf3,0xd9,0x93,0xe3,0x83,0xc8,0x84,0x3b,0x33,0x8f,0x07,0xe0,0x79,0x3f,0xdb,0xbb,0x2e,0x88, +0x0c,0xc8,0x6e,0xe6,0xd1,0x8a,0xea,0x1b,0x87,0x9f,0x7d,0x66,0xe2,0x91,0x69,0xae,0x9c,0x9f,0xb5,0xe2, +0x8f,0x39,0x7e,0x07,0xe2,0xad,0x33,0xad,0x67,0xf7,0x13,0x7d,0x3b,0x33,0xbb,0xfa,0xfe,0xfe,0x5b,0x19, +0x19,0x07,0xfc,0xf1,0x2c,0xb4,0x58,0x63,0xb0,0xa9,0x67,0xcc,0x19,0x75,0xe6,0xaa,0xab,0x32,0xb3,0x70, +0x34,0x74,0x5e,0x16,0x23,0x3e,0x09,0x78,0x75,0x6c,0x14,0x63,0xb1,0x2b,0xb7,0x64,0xf1,0xef,0x50,0xba, +0xa0,0x2b,0x3f,0x7a,0xd7,0xfd,0x5d,0xa0,0xc4,0x15,0x1d,0xdf,0x54,0xaf,0x3a,0xbf,0x8c,0xfe,0xc4,0xc5, +0xf5,0x1f,0x76,0x7c,0x3a,0xfc,0xd3,0xb0,0x0f,0xd2,0x9f,0x4f,0xda,0xfa,0x00,0xc7,0x8d,0x11,0xbd,0xca, +0xe3,0x0b,0xea,0xd0,0x3d,0x43,0x8b,0x7e,0xa6,0xaf,0xea,0x43,0xdc,0xf9,0x5e,0xc6,0xef,0xc0,0x1a,0xc0, +0xf1,0x0e,0x13,0x06,0x51,0x61,0x13,0x99,0xda,0xb0,0x3f,0x61,0x58,0x4a,0x5f,0x23,0x35,0xa0,0xa5,0x35, +0xec,0x5d,0xaf,0x91,0x1c,0xd1,0x4e,0x28,0xf9,0xb3,0x5d,0xa3,0xc0,0xd1,0x50,0x16,0x5d,0xb3,0x83,0xbf, +0x54,0x2c,0x9f,0x11,0xa4,0x50,0x36,0x47,0x0c,0xc6,0xd9,0x31,0x30,0xb1,0x0a,0xf7,0xdc,0xce,0xca,0xbc, +0xf2,0x9d,0x40,0x77,0x06,0xe5,0xd4,0x5a,0x3a,0xa6,0xcb,0x7a,0xa3,0xdd,0xc5,0x54,0x19,0xfc,0xd1,0x72, +0xba,0xb2,0x79,0xe8,0x07,0x80,0xae,0xd1,0x5f,0xfa,0xc3,0x87,0x81,0xc3,0x98,0x12,0xb4,0x07,0x28,0x99, +0xba,0x4e,0x6f,0xf6,0x83,0xd7,0xe1,0x73,0xfd,0x6e,0xb3,0x79,0x3e,0xbc,0x89,0xcf,0x7f,0x4d,0xca,0xd7, +0xf5,0xc4,0x78,0x71,0x9d,0xfd,0xde,0xf1,0x34,0xeb,0x4a,0x59,0x34,0x1e,0x7a,0x8c,0xa5,0x6a,0x4f,0xbf, +0xd3,0x61,0x15,0x3a,0x31,0x5e,0x70,0xf2,0xf0,0xb5,0xf6,0xb3,0x66,0x39,0x4b,0x75,0x37,0x2d,0x7a,0x58, +0xea,0xdc,0xb2,0x77,0xaa,0x65,0xbd,0x10,0x92,0x2a,0x4c,0xeb,0xb7,0xe1,0x5b,0xd3,0x63,0x16,0x77,0xfb, +0x56,0xd9,0x25,0x6d,0x40,0x15,0xbe,0x0b,0xdf,0x75,0xa5,0x79,0x67,0xa7,0x29,0x4d,0x87,0x3c,0x67,0x8f, +0x6d,0xe2,0xb1,0x34,0x51,0xff,0x36,0x2b,0x12,0x54,0xdc,0xf3,0x5f,0xc2,0x78,0xce,0x4e,0x27,0x40,0x7d, +0xde,0xa4,0xe3,0xe8,0x09,0xbf,0xac,0x99,0xb6,0x4c,0xe2,0x26,0x75,0x1f,0xc0,0x04,0xa6,0xac,0x9b,0xe4, +0x8c,0x2d,0xf1,0x2a,0xf5,0x65,0xcf,0xed,0xe5,0x6d,0x08,0xc4,0x1e,0x90,0xe4,0x55,0xd1,0x93,0xd4,0x42, +0x3a,0x04,0xa0,0xd5,0x8e,0xba,0xef,0xef,0x1f,0x7e,0xb1,0xbf,0xf3,0x2d,0x3b,0x4d,0x34,0x0f,0x50,0xd8, +0x55,0x7b,0x5a,0x41,0x6e,0xd7,0x91,0x2d,0xae,0x2d,0x32,0xa1,0x37,0xaa,0xb4,0xf6,0xfe,0xf7,0x61,0x39, +0x69,0xe5,0x13,0xdb,0x92,0x5a,0x88,0x8c,0xfd,0x91,0x8a,0x59,0xd3,0xdb,0x59,0xa7,0x01,0x02,0xa9,0x74, +0xbf,0xaa,0x88,0xc9,0x34,0x20,0xa2,0xa6,0x8b,0xe1,0x03,0x64,0x51,0xdb,0x14,0xd2,0x9b,0xec,0xee,0x82, +0xd2,0x0b,0x0e,0xfd,0xc3,0xfd,0x94,0xfa,0xf7,0x94,0x7d,0x74,0x9e,0xc5,0xe0,0x83,0x00,0xfc,0xb4,0xb3, +0x22,0x2e,0x17,0x94,0x4e,0x62,0xd1,0x60,0xc4,0x2d,0xb5,0xc6,0x03,0x98,0x33,0x3e,0xf0,0x63,0x0f,0x06, +0xda,0x4a,0xcf,0x51,0xee,0x4a,0x45,0xd5,0x3b,0x0c,0x9e,0x42,0x99,0xf9,0x94,0xbe,0x18,0xf0,0x2f,0xd5, +0x6a,0x14,0x7c,0xbe,0x9f,0xe2,0xfb,0xc3,0xae,0x21,0xda,0xd9,0xb5,0xc6,0xae,0xbb,0x1a,0x39,0x26,0x82, +0xac,0xdb,0x22,0x04,0x8c,0xcd,0x3a,0x9c,0x96,0x6c,0x4e,0xd0,0x03,0x8a,0x93,0xf1,0xa2,0xe5,0x36,0x99, +0x6a,0x53,0xcd,0x12,0xdc,0x64,0xdd,0x55,0x64,0x90,0x0a,0x76,0x26,0xd5,0xca,0x73,0xf1,0xab,0x57,0xd6, +0xfd,0x6c,0x92,0x65,0xcf,0xa0,0xc2,0xf2,0x45,0x57,0x89,0xca,0x56,0xa2,0x75,0x33,0xd1,0x18,0xc0,0x31, +0xec,0xd8,0x0c,0x73,0x8d,0xbc,0x32,0x3f,0xc9,0x27,0x91,0xcb,0xa0,0x32,0x78,0xe3,0x05,0x2a,0xd9,0x03, +0x54,0x78,0xad,0xaf,0x0f,0x83,0xd1,0xd6,0x7f,0xe1,0x05,0x2f,0xb6,0x7e,0xa9,0x37,0x3c,0x9b,0xac,0xaf, +0x6c,0xea,0xd9,0x1a,0x01,0xba,0x48,0xf9,0xe3,0x59,0x1f,0x98,0xdd,0xb3,0xfe,0x21,0x8c,0x37,0x3a,0x26, +0xa1,0x36,0xbb,0x05,0x00,0x28,0xb5,0x4d,0xb3,0x33,0x73,0xda,0xd4,0xc2,0xcf,0x1e,0x1c,0x82,0x7c,0xf1, +0x5b,0x1b,0x33,0x11,0x78,0x6c,0x2a,0x9a,0x1a,0x53,0xd1,0x77,0x34,0x2c,0xef,0x64,0xcf,0x49,0x99,0x56, +0xb3,0x8d,0x47,0x11,0xef,0x00,0x42,0x1f,0x91,0xc6,0x99,0x5d,0x33,0x15,0x05,0xd6,0x66,0xd3,0xb1,0xd3, +0x62,0xa2,0xea,0xbd,0x48,0xd9,0x12,0x57,0x0f,0x2a,0xac,0x67,0x43,0xe0,0x56,0xf1,0x4c,0x4c,0x07,0xa5, +0xfe,0x0b,0xe9,0x1d,0x00,0x1d,0x19,0xcd,0x16,0x3a,0x4a,0xef,0x46,0x9d,0xd2,0xb6,0x4f,0x74,0xd2,0x4b, +0xe5,0x46,0x5a,0xb2,0x94,0xa1,0x91,0xc3,0xfd,0xdf,0xaa,0xed,0xa4,0x66,0x83,0xd8,0xb0,0xe3,0x9e,0x89, +0xc5,0xe1,0x37,0xd2,0x45,0x76,0x4a,0xbf,0x91,0xd2,0x9b,0x88,0x90,0xb3,0xf7,0x46,0x33,0x17,0x7a,0xa2, +0x55,0xde,0x5f,0x93,0x3c,0xb0,0x85,0x21,0x34,0x20,0x6f,0x26,0x0d,0xe6,0x9a,0x16,0x06,0xbb,0xd9,0xb7, +0x58,0xae,0x12,0xa3,0x98,0x0b,0x64,0xca,0x45,0x12,0x2f,0x26,0xb9,0xb0,0x5e,0x8c,0xc9,0x8e,0xe6,0xc7, +0x05,0x11,0xb9,0x75,0x7b,0x73,0xdd,0x81,0x35,0xe7,0x14,0xb1,0xe6,0xe5,0x2f,0x60,0xef,0x5e,0xfb,0xa0, +0x15,0xbc,0xec,0xfd,0x47,0x1a,0x99,0xdb,0x3d,0x4e,0xe9,0xef,0xad,0x53,0xc4,0x83,0xbe,0x4c,0x93,0xdf, +0xe3,0xc5,0x5e,0x7c,0xbb,0x02,0x86,0x09,0x1c,0xc6,0xf6,0x9c,0xbe,0xe4,0x58,0x29,0x25,0xbb,0x84,0x5f, +0x60,0x2c,0x64,0x83,0xe1,0xb5,0x4f,0x1b,0x0f,0x4d,0xb4,0xb8,0xa4,0x49,0xf6,0x6c,0x0d,0xbb,0x0a,0x22, +0xfa,0x0a,0xff,0x69,0xa8,0xb6,0xd2,0xf7,0x0c,0xa9,0xce,0xd6,0x9c,0x22,0x5b,0x05,0xf9,0x82,0x17,0xee, +0xf7,0x9e,0xff,0x9b,0x31,0xe1,0x8a,0x15,0xd3,0xc5,0x87,0x0b,0x23,0x0b,0xb8,0x30,0x32,0xe5,0x23,0x3f, +0x51,0x50,0x76,0x62,0x6b,0xaa,0xdd,0x26,0x5d,0xd8,0x99,0xfa,0x87,0x46,0x69,0xfa,0x54,0x4c,0x14,0xe2, +0xad,0xff,0xb5,0xf0,0x7b,0x88,0x67,0xd0,0x59,0x7f,0xc7,0x31,0x1b,0xa4,0x89,0x45,0xc5,0x48,0x3b,0x77, +0xca,0x0c,0x8c,0x36,0xc3,0x2f,0xe5,0xe7,0x90,0x6f,0x15,0xe0,0x5d,0xd3,0x71,0xc7,0xc6,0x44,0xae,0x70, +0xb0,0xad,0x87,0x5c,0x6b,0x18,0x05,0x54,0x08,0xd5,0xe3,0x78,0x8c,0x07,0x96,0x8d,0xaa,0x97,0xf6,0xc3, +0xaf,0xc1,0xb7,0x69,0xab,0xef,0x47,0x52,0xf4,0xe7,0xb6,0x01,0xbc,0xd4,0x94,0x71,0x83,0x6b,0xd6,0x6b, +0xb1,0xe2,0xf0,0x39,0x8f,0x0a,0x08,0x36,0x25,0x86,0x94,0xa5,0x98,0xb2,0xaf,0x14,0xe1,0x9d,0x65,0xc2, +0x1c,0x3c,0x1e,0x29,0x00,0xa4,0xb7,0x45,0xbc,0x5e,0x64,0x41,0xee,0xf3,0x3e,0x14,0xd0,0xb1,0x50,0x2d, +0x0c,0xf8,0x41,0x82,0xa5,0xc5,0xaf,0x36,0xb9,0x08,0xee,0x9c,0x27,0x4e,0xd0,0x96,0x44,0x8b,0x23,0x2f, +0xdc,0xd8,0x20,0x08,0x6f,0xbd,0xa7,0xc7,0x7d,0xf3,0x38,0x8f,0x3f,0x24,0xd9,0xba,0x50,0x8d,0xaf,0x7d, +0xfb,0xef,0x5d,0x89,0xb6,0x5b,0x9f,0x1e,0x09,0xb8,0x41,0x70,0xc7,0x4a,0xac,0x2e,0xf9,0x16,0xec,0xe5, +0xf0,0xa7,0x21,0x3c,0xf2,0xe3,0xe9,0xa3,0x19,0x51,0x0a,0x8c,0x80,0x1b,0x4f,0x3f,0xe7,0xbf,0x8f,0x67, +0x0c,0x98,0xdd,0x4c,0x0a,0x36,0x8d,0x67,0xe0,0x91,0x84,0x8b,0xa1,0x0f,0x61,0xf4,0x8e,0x0b,0x36,0x06, +0xf7,0x2b,0x15,0xc1,0xe7,0xb4,0x54,0x44,0x3b,0x76,0x6f,0x5d,0xea,0x91,0x40,0x9c,0x54,0x30,0x73,0xf9, +0x95,0xce,0xe9,0x91,0x37,0x51,0xb5,0x53,0x8b,0xd9,0x8d,0x19,0x53,0x0d,0x75,0x0d,0xfb,0x2e,0x7e,0x26, +0xa8,0x31,0x2e,0xbf,0xa0,0x54,0x87,0x5e,0x70,0xf4,0xd0,0x75,0xa0,0xaf,0x92,0xbc,0x18,0xda,0x37,0x5b, +0x2c,0xf4,0x1d,0x62,0x22,0x50,0x7a,0xfe,0xf6,0x2f,0x33,0xaa,0xfd,0x5f,0x5b,0x09,0x02,0xfc,0x80,0xbc, +0xa9,0x15,0xb8,0xd5,0x9a,0xc0,0xae,0x65,0xd3,0x43,0xe9,0x00,0x5a,0x38,0x32,0xc6,0xed,0x8b,0x78,0xc8, +0x5d,0xa0,0x4c,0xff,0x91,0x89,0x04,0xf2,0xe2,0xf6,0x4c,0x62,0xb6,0x4e,0xac,0xf5,0x78,0x40,0xdb,0xf0, +0x45,0xac,0xcf,0x2f,0x86,0xae,0x78,0x4f,0x47,0x4a,0x6f,0xe4,0xc9,0x4d,0xaa,0xa1,0x0d,0x5c,0x62,0xb4, +0x8d,0x21,0xee,0xa0,0xf4,0x06,0xfa,0xda,0xe3,0x81,0x19,0xcd,0x04,0xae,0x59,0xf7,0x61,0x89,0x26,0x53, +0x69,0xa9,0xf5,0xc4,0x1e,0xad,0x47,0xb0,0x03,0xf3,0x2f,0xd4,0x14,0x82,0x9e,0xf4,0xd3,0x52,0xc7,0x6e, +0x53,0x6f,0x91,0x16,0xb5,0x63,0x72,0xf5,0x6a,0x62,0xa8,0xff,0x72,0x4c,0x42,0x88,0x1c,0x59,0xbd,0xdb, +0xae,0xd7,0xef,0xca,0x77,0xa4,0x0e,0x18,0x6d,0xeb,0xf3,0xdc,0x9f,0x2a,0x6d,0x35,0xfd,0x55,0x4a,0x3c, +0x28,0x20,0xd1,0xad,0xbf,0x77,0xc7,0xf4,0x53,0x48,0x4b,0x1d,0xfb,0xda,0xbc,0x92,0x38,0x59,0x37,0x34, +0x7c,0x9f,0x14,0xb6,0xde,0x8b,0x12,0x05,0x23,0x3a,0xbf,0xb1,0x7a,0x7d,0xdb,0xef,0xc2,0x3c,0xd6,0x60, +0xd4,0xa1,0x90,0x03,0x6e,0x62,0xc1,0x21,0x88,0xb5,0x52,0x36,0x01,0x23,0x08,0x0a,0x3c,0xe8,0x01,0x81, +0x38,0xeb,0x63,0x5b,0x77,0xe4,0xd1,0x04,0xc0,0xc7,0xb4,0x8f,0xf4,0xf4,0x6d,0x8f,0x6f,0x7f,0x52,0xb7, +0x44,0x67,0x71,0xe4,0x20,0x33,0xd5,0x88,0x7b,0x72,0x1e,0x56,0x2f,0xed,0x17,0x4f,0x88,0x8e,0x74,0x1e, +0xd8,0xef,0x64,0x46,0x0d,0x72,0x3d,0x1d,0xa5,0xa8,0x7f,0xab,0x24,0x2e,0x83,0xa5,0x98,0x89,0x14,0xc5, +0xd8,0x12,0x59,0x41,0xe8,0x35,0x73,0xdd,0x84,0x1a,0xf5,0x3a,0x13,0x96,0x2f,0x33,0xb3,0x55,0x67,0xde, +0x3f,0xe4,0xec,0xfb,0xce,0xc0,0xe1,0xf9,0xdb,0xdc,0x6f,0x1a,0xd8,0xdd,0x21,0x6f,0x2f,0x4c,0xd3,0x55, +0xf3,0x1e,0x20,0xd3,0x50,0x5f,0xdb,0xcf,0x07,0x9f,0xc3,0xda,0xca,0x51,0x2a,0x7a,0xf6,0xc3,0xb6,0xa3, +0xb6,0xa8,0x0e,0x4a,0x26,0xed,0x59,0xd3,0xeb,0xd9,0x5c,0xc5,0xbd,0x96,0xda,0xfe,0xc2,0x87,0x35,0x6b, +0xc6,0xc8,0xef,0x8e,0x75,0xe2,0x39,0x1d,0xc7,0xc0,0x87,0x3a,0x7b,0xf2,0x11,0x1e,0xa1,0xbb,0xec,0xa7, +0x61,0xff,0xba,0x26,0x42,0xb9,0xf0,0x6f,0xd9,0x33,0xf8,0xc2,0xfd,0x60,0xdb,0x9c,0x8e,0x2f,0xc7,0x72, +0xb1,0xa2,0x56,0xad,0xc2,0xd5,0xf4,0x52,0x44,0xe0,0xc5,0x64,0xb5,0x7b,0xfd,0x7d,0x0c,0xd0,0xf0,0x55, +0x93,0x04,0xa6,0xec,0xaf,0xc2,0x4b,0xea,0x29,0x44,0xce,0x0d,0x39,0x68,0x61,0xef,0x0a,0xc0,0xab,0x56, +0x6b,0xb6,0x66,0xfd,0x53,0x21,0x57,0xe1,0x34,0x9a,0x7c,0xb0,0x0e,0xfc,0xe0,0x43,0x15,0xaf,0x89,0x91, +0x2f,0xaf,0x75,0xe5,0x3e,0xf8,0x17,0x54,0x39,0xb6,0x2e,0x5f,0xd9,0xd6,0xe5,0xab,0x86,0x75,0xf9,0xaa, +0x61,0x5d,0x0e,0x53,0xf1,0x58,0x80,0xb6,0x16,0x61,0xdd,0x5c,0x9c,0x3a,0x64,0x81,0xab,0xa3,0x99,0xbf, +0xc2,0xd5,0x07,0x4b,0xbf,0x3b,0x5d,0xcc,0xa8,0x37,0xfa,0x7d,0x7a,0xbc,0xa2,0xff,0xa9,0x57,0x28,0x77, +0x4a,0x1f,0x8e,0x68,0x71,0x5e,0xc1,0x4e,0x8b,0xf6,0x38,0x6d,0x08,0xbf,0xb2,0xe4,0xde,0xfd,0xfe,0x2d, +0xa5,0x67,0x5e,0xf3,0x0e,0x25,0xc3,0x02,0x7f,0xe1,0xdf,0xce,0x94,0x15,0x9e,0xa1,0x5b,0xae,0x69,0x26, +0xc3,0x83,0xed,0x7f,0xa4,0x55,0xb0,0x6c,0x66,0xb7,0x6e,0x09,0x29,0xfa,0xa9,0x86,0xe0,0x90,0xb8,0x67, +0xc0,0x7b,0x3c,0xe0,0xbd,0xda,0x80,0x13,0x19,0x4f,0x2d,0xa5,0xac,0xd0,0x8e,0xff,0xac,0x0d,0xba,0x77, +0x6e,0xe9,0x2c,0x85,0x66,0x16,0xb1,0x11,0xcd,0xbe,0x75,0x3b,0x08,0x13,0x6e,0x04,0xad,0xf4,0xdb,0x3f, +0xe7,0x74,0x31,0xda,0xdf,0xbf,0x3d,0xc8,0x9f,0x84,0xa3,0xed,0xb6,0xe3,0xe0,0xb5,0x1c,0x9d,0x89,0xb7, +0x59,0x31,0xa9,0x56,0x70,0x17,0x9d,0x40,0x24,0xfa,0x5c,0x61,0x2a,0x36,0x5a,0x66,0x11,0x11,0xb4,0x5b, +0x2b,0xcd,0x39,0x91,0xf9,0xf2,0xbd,0x90,0xf8,0x15,0x7e,0xdb,0x0f,0x33,0x98,0x3c,0x7b,0x41,0x66,0x6c, +0x12,0x81,0x9d,0x31,0x8d,0x7d,0x78,0xbe,0xfb,0xe9,0xcc,0xb7,0x8b,0x6a,0x98,0xf8,0xb9,0x4d,0xaf,0x86, +0x89,0x65,0xec,0x5e,0xd3,0xf8,0xc3,0x3c,0x3a,0xe3,0x06,0xd9,0x78,0xe1,0xec,0x4d,0x43,0x3c,0x12,0xc0, +0xb8,0x92,0x69,0xc4,0xf4,0x4e,0x0e,0xbb,0x6d,0xc1,0x71,0xc5,0x93,0xad,0xd7,0x75,0xa2,0x22,0xab,0x11, +0x47,0x89,0x09,0x32,0x50,0x86,0xd2,0x33,0xc1,0x5d,0x9a,0x95,0x41,0xee,0xb6,0x8f,0x4f,0x38,0xf4,0x88, +0x2a,0xe8,0xdb,0x0e,0xbf,0xc0,0xca,0xd7,0x1c,0xbd,0x51,0x6f,0x42,0xdd,0x81,0x01,0x6e,0x07,0x89,0x96, +0x0f,0xe4,0x6c,0x88,0x5f,0x54,0xf6,0x89,0x05,0xdb,0xa6,0x23,0x26,0x99,0x78,0x1c,0xc4,0x0c,0x8e,0xe7, +0x22,0x40,0x17,0xa2,0x60,0xd4,0x9a,0x42,0x5f,0x67,0xd5,0x31,0xcc,0xb4,0x8c,0x9f,0x60,0x07,0x45,0xce, +0x19,0xfa,0x89,0x1f,0xf2,0x6d,0x2f,0x95,0x19,0x0d,0x25,0x1c,0x0d,0x40,0xa3,0x85,0xcd,0x83,0xb3,0x21, +0xc9,0xb0,0xf8,0x73,0x4c,0x4f,0xc5,0x9f,0x77,0xe7,0x11,0xb7,0xe8,0x1f,0x0b,0x09,0xc8,0x30,0xa1,0xa5, +0xcd,0xdf,0xb0,0x0b,0x17,0x74,0x09,0x60,0xb5,0x36,0x1b,0x70,0x20,0xd5,0x29,0x27,0x26,0xe9,0x58,0xd9, +0x51,0x7a,0xd9,0x5d,0xe4,0x4a,0xfb,0x8c,0x32,0x75,0xb0,0x63,0xe6,0xf2,0xe7,0x3c,0x6f,0xfd,0x76,0x15, +0x1b,0x07,0x43,0xcb,0xb3,0x0e,0x01,0x47,0x59,0xfb,0xf9,0x66,0x52,0x0e,0x39,0xa7,0xa6,0x9f,0xec,0xed, +0xf5,0x32,0xc0,0x0b,0x29,0xbf,0xfe,0x4e,0x9e,0x1b,0x33,0xd3,0x30,0x6d,0x05,0x88,0x65,0x3f,0x36,0x0e, +0x36,0x5b,0xb5,0x9b,0x4f,0x6b,0x15,0xc5,0xd4,0xad,0xcb,0x4f,0xbd,0xa6,0x97,0x63,0xe5,0xf4,0x34,0xfe, +0x5f,0xe8,0xab,0x32,0xca,0x6b,0xf0,0x53,0x46,0xa2,0x4c,0xf3,0x2c,0x9b,0x47,0x22,0xce,0xad,0xae,0xb1, +0x24,0xaf,0x6a,0x2a,0x6c,0x8d,0x02,0xc9,0xa5,0x24,0x0b,0xe2,0xdd,0xb2,0xac,0x13,0xce,0x0a,0x32,0xbe, +0xe7,0x44,0x11,0xc3,0x20,0x76,0xd7,0xfb,0x17,0xf5,0x50,0x77,0x10,0x3f,0xbd,0x40,0x91,0xcf,0xd9,0x8a, +0x76,0x53,0x5d,0xf3,0x86,0xdb,0xeb,0xa9,0x18,0x58,0x10,0x32,0x41,0xa9,0xb4,0xd9,0xfc,0x9b,0x1e,0x44, +0xe7,0xec,0xb2,0xc9,0x40,0x4a,0xac,0xc0,0x08,0x96,0x2e,0xed,0xe3,0xbe,0xd6,0x67,0xe0,0x16,0x4e,0x0b, +0x2a,0x54,0x56,0x17,0x59,0xfe,0x07,0x7d,0x2f,0x4b,0xd4,0xc1,0x04,0xdd,0x02,0xc7,0xb3,0x52,0x78,0x04, +0xfa,0x95,0x56,0xf8,0x6d,0x7d,0x7d,0xd5,0x4d,0xb2,0xdb,0x3e,0x91,0xf6,0x9d,0xc9,0x80,0x9b,0xe4,0x57, +0xf7,0x6c,0xbf,0x45,0x2d,0x04,0x02,0x4c,0x2d,0xcb,0x3f,0x24,0x01,0x60,0x1c,0x40,0x3d,0x25,0x8e,0xbf, +0xe8,0xc2,0x87,0x91,0x3a,0x74,0xd4,0xb6,0x67,0xce,0x06,0x09,0x00,0xc0,0x1a,0xe0,0x2b,0x86,0x71,0xdc, +0x81,0x0f,0xa6,0xa2,0x95,0xe9,0x4e,0x05,0xee,0x03,0x7a,0xb0,0x2b,0xf5,0x55,0x57,0x6a,0x31,0x57,0xfc, +0x6f,0x0e,0x94,0xe5,0xc4,0xaa,0x27,0x8d,0xf5,0xa8,0x84,0x21,0xf7,0x6d,0x17,0x8a,0x4e,0x33,0xab,0x5d, +0x65,0xaa,0x30,0x6b,0x55,0xfe,0x30,0x92,0x62,0xce,0x81,0xc1,0x12,0x3b,0x43,0xef,0x21,0xf6,0x81,0xfa, +0xa6,0x29,0x15,0xd4,0x60,0x65,0x73,0xb7,0xc5,0xf7,0xc1,0xeb,0xcd,0x13,0x9c,0xb2,0x79,0xe3,0x00,0x54, +0x09,0xca,0xc1,0x21,0x92,0xc4,0xbf,0x35,0x12,0x54,0x72,0xe7,0x69,0x7a,0x3c,0x9a,0xa4,0xfd,0x32,0x48, +0x39,0x21,0x31,0xf6,0xad,0xbc,0x2c,0xb3,0xf8,0x71,0x7a,0x5c,0x8e,0x53,0xc4,0xda,0x89,0x9b,0x26,0x09, +0x00,0xe2,0x20,0x3e,0xff,0x9e,0xaf,0x0f,0x3f,0xf1,0xf5,0xb2,0xd9,0x8c,0x1a,0xb4,0x4b,0x68,0x2a,0x3a, +0x1e,0x0c,0x40,0xba,0x8c,0x75,0x2e,0x79,0x2d,0x97,0xcb,0x3f,0x9a,0x4b,0xbf,0x9f,0x53,0x75,0x3a,0x33, +0x61,0x23,0x1c,0x3d,0xb7,0x89,0xb1,0x09,0xad,0x99,0xfe,0x1b,0x8b,0xd6,0x6e,0xf6,0x92,0xf4,0x2e,0x8f, +0x16,0x49,0x06,0xc8,0x2c,0x5e,0xf7,0xe7,0xd9,0x2d,0xae,0x89,0xd1,0x8f,0xf1,0xbb,0x22,0xe6,0xf3,0x26, +0xcb,0x17,0xb8,0x4e,0xae,0xa3,0x4b,0x3c,0xdc,0x7a,0x15,0x39,0x75,0x33,0x0b,0x0b,0xf7,0xc6,0xab,0x72, +0x2b,0xd6,0xe7,0xd7,0x09,0xe4,0x51,0x7e,0x1e,0x13,0xe9,0xd3,0x4e,0xbe,0x46,0x72,0x7d,0x7e,0x59,0x08, +0x84,0xda,0xa0,0xa9,0xa8,0xaa,0x59,0xa3,0x9e,0x98,0x5f,0x5f,0xf9,0xef,0x79,0x6a,0xfd,0x1a,0x43,0xf8, +0x1a,0xb6,0x89,0xbd,0x46,0x1c,0x94,0xf0,0x47,0xcd,0xfa,0x33,0x7e,0x82,0xd1,0x7d,0x8d,0x82,0xb9,0x11, +0xa7,0x4a,0x60,0x50,0xa2,0x20,0xd6,0xec,0x36,0x87,0xe2,0xb5,0xac,0x6c,0x5c,0x10,0x27,0x44,0xcc,0x5c, +0x0f,0xa8,0x17,0x0a,0xe3,0xa3,0xf0,0x18,0x39,0x8d,0x63,0x24,0x6a,0x74,0xd3,0x04,0x92,0x14,0xc5,0xce, +0x6e,0x36,0x85,0xe7,0x2b,0x4f,0x9b,0x8c,0x72,0x84,0x23,0x13,0xd0,0xd4,0x28,0x8b,0x65,0x95,0x05,0x8b, +0x67,0x13,0x03,0x2f,0x9b,0x49,0x7a,0xe5,0x51,0x95,0x0b,0x9a,0x15,0xe7,0x6a,0x93,0x5b,0x7b,0x6c,0x8c, +0x50,0x15,0x6b,0x58,0x68,0x69,0x03,0x63,0xef,0xe8,0x6e,0xf4,0x50,0xe7,0x05,0x30,0x78,0xac,0x6a,0x2f, +0xe9,0x56,0x5a,0x83,0x2b,0xc8,0x85,0x19,0x5b,0xf7,0x13,0xf5,0x88,0x7c,0xa5,0x66,0x09,0x92,0x5d,0xc5, +0x33,0x88,0x8a,0x20,0x46,0x99,0xe8,0xe2,0x13,0x83,0xc3,0x5e,0x4c,0x8c,0x98,0xcc,0x0b,0x10,0x52,0x61, +0xed,0x99,0xde,0xdf,0xfa,0xdf,0x86,0xa2,0x23,0xa4,0x19,0xd7,0x50,0x5b,0xd4,0xcc,0x90,0x18,0x11,0xe9, +0x3b,0x6b,0x38,0x7b,0x8a,0x5d,0x15,0x69,0xce,0x7b,0x81,0x28,0x09,0xeb,0x21,0xc6,0xb2,0xf0,0x96,0x03, +0x2d,0x53,0xcb,0x98,0x3a,0xd5,0x6e,0xab,0x41,0x15,0x5f,0x97,0x32,0xa5,0xd2,0xce,0xdd,0x84,0x1d,0xd1, +0x32,0x23,0xf3,0x0d,0x63,0xcb,0x3a,0xe9,0x99,0x11,0x06,0x87,0x6d,0xfa,0xb6,0x09,0x81,0xdb,0x85,0x28, +0x06,0xd0,0x86,0x79,0x08,0x67,0x26,0xaa,0x68,0xb8,0x34,0xa5,0x40,0x13,0x63,0x63,0xd8,0x80,0xba,0x99, +0xeb,0x7e,0x65,0x9e,0x9c,0xd8,0x3a,0x22,0x65,0xe7,0x96,0xac,0x0e,0xb5,0x54,0x64,0xe9,0x11,0x6d,0xd3, +0x2f,0x9f,0x61,0xc3,0x75,0x23,0x09,0x24,0xa1,0xf6,0xea,0x2f,0x1b,0x58,0x10,0x6f,0xe0,0xbc,0x66,0x3c, +0xff,0x32,0x16,0xac,0xb2,0xab,0x21,0xab,0xaa,0x43,0xd7,0x58,0xeb,0xb9,0x91,0x56,0xaa,0xd9,0xb3,0x4f, +0xd1,0xb3,0x25,0x83,0x6b,0x23,0x4c,0xab,0xdf,0xb3,0xbc,0x87,0x96,0x2c,0x79,0xac,0xd1,0x69,0x7e,0xe5, +0xca,0x97,0xe9,0xd9,0x25,0x8a,0x1a,0xdd,0xb8,0xad,0xd8,0xdf,0x2d,0x70,0x92,0x57,0x0e,0x06,0x06,0xbc, +0x7c,0x64,0x78,0x2a,0xf8,0x4f,0x33,0xe4,0x4d,0x06,0x2f,0x67,0xdb,0x81,0x11,0x61,0x84,0xa4,0x15,0xe2, +0xbc,0xbe,0x0e,0xa5,0x19,0x8a,0x83,0xc8,0x69,0xaf,0xb9,0xaf,0x35,0x1a,0x71,0x25,0xd3,0x3e,0xa6,0x9d, +0xc8,0x2b,0x0a,0x60,0x26,0xd3,0x5a,0x93,0xc4,0x3f,0x44,0xeb,0x72,0x63,0x15,0xc1,0x21,0x37,0x7a,0x1d, +0xe0,0x36,0x39,0x20,0x73,0x14,0x8f,0xaf,0xa8,0xff,0xe5,0x66,0x43,0x3c,0x14,0x02,0x3e,0xba,0x39,0x2b, +0xc9,0x68,0x06,0x21,0x26,0xf8,0xfd,0xe0,0x2f,0x0c,0x66,0x66,0x6b,0x83,0xc2,0x1f,0x34,0x98,0x88,0xe3, +0x69,0x5d,0x90,0x32,0xc8,0x60,0x93,0xd4,0x1f,0xfc,0xb6,0x46,0x29,0xec,0xf5,0x7e,0xf3,0x5f,0xb9,0x9e, +0x5f,0xd7,0xd0,0x77,0xdb,0xe2,0x1e,0xde,0x63,0xef,0x70,0x0f,0xb6,0x4a,0xdb,0x56,0xca,0x50,0x84,0x5d, +0x26,0x53,0x7f,0x12,0xfb,0x28,0xc7,0x77,0xfe,0x24,0x74,0x46,0x45,0xe4,0x35,0x08,0x0c,0xa4,0xc7,0xe6, +0xb7,0xd9,0x64,0x42,0x6d,0x6c,0x98,0x3e,0x96,0xa8,0x56,0x1b,0x89,0x74,0xe5,0x37,0x8f,0x4b,0xec,0x11, +0x69,0xa5,0x00,0xaa,0xeb,0x17,0x7d,0xc7,0x48,0xee,0xea,0xa4,0xca,0xe4,0x30,0x38,0x12,0xeb,0xea,0x4a, +0x43,0xd9,0x34,0xc1,0xe9,0x6c,0x15,0x93,0x54,0x07,0x6c,0x80,0x67,0xb5,0xa3,0x6e,0x7c,0xc5,0x2b,0xc0, +0x61,0xac,0x4a,0xe7,0x13,0x4d,0x96,0xa4,0xba,0xcd,0xea,0xc3,0xce,0x26,0xd2,0x1e,0xf0,0x49,0x72,0xae, +0xea,0x06,0x3b,0x36,0xee,0xae,0xe1,0x52,0x90,0x7e,0x8d,0x1a,0x55,0x06,0x54,0x52,0xa9,0x32,0x6e,0xd5, +0x87,0x8f,0xe0,0x71,0xbd,0xe3,0x81,0xf3,0xc9,0x10,0xd5,0x8d,0x8e,0xfe,0x8f,0x14,0xbc,0x88,0xe7,0x08, +0x95,0x35,0x47,0x41,0x4d,0x17,0xe1,0x79,0x2c,0xa8,0xa1,0xab,0x9c,0x2e,0x2b,0x7d,0x9d,0x7e,0x38,0x75, +0x02,0x47,0x21,0x91,0xae,0x72,0x43,0x56,0xd0,0xbd,0xa5,0xa1,0x35,0x77,0xc8,0xa1,0x7a,0xee,0x5f,0x8a, +0x2a,0x12,0x4f,0x95,0x32,0x54,0x10,0xe5,0x7e,0x7c,0xfd,0x8a,0xd6,0x04,0x1e,0xf3,0xb5,0x6f,0x45,0x1d, +0xc5,0x43,0x7d,0xcd,0x55,0x60,0x5d,0xb4,0x31,0x7c,0x38,0xd7,0x4f,0x58,0xe3,0x7e,0xd3,0x76,0x0b,0xaa, +0x08,0x3c,0x3e,0xf2,0x8c,0xc6,0x3c,0x1d,0x83,0x07,0x42,0x08,0x42,0x81,0x31,0xb3,0xf4,0xae,0x5a,0xe0, +0x58,0x3d,0x92,0x70,0x3a,0x40,0x67,0x65,0xe3,0xd3,0x02,0x66,0x0e,0x0a,0xcb,0x51,0x21,0x04,0x1a,0x95, +0x6f,0xbe,0x6d,0xfb,0xf6,0x54,0x94,0xee,0x74,0xd6,0xc1,0x6a,0x35,0x41,0x87,0xe2,0x1e,0xb3,0x23,0xa9, +0xce,0xda,0xd6,0xa0,0xc6,0xa6,0xe7,0x79,0x13,0xae,0x6d,0xf4,0xf0,0xe9,0x39,0xf8,0xe9,0x58,0xd0,0xab, +0xa7,0x3f,0x9d,0x1d,0x9c,0x8d,0x9e,0x04,0xec,0xf6,0x59,0x9e,0xe5,0x67,0xe9,0xd9,0xc5,0xec,0xa1,0x37, +0xad,0xdf,0x9f,0x1d,0x4c,0x9e,0xb8,0x93,0xe0,0x98,0xd2,0x1e,0x3e,0xd9,0xb0,0xbb,0xd7,0xaf,0xc8,0x64, +0x38,0xfd,0x29,0xf8,0xd3,0xd9,0xf4,0x6c,0xe8,0xcf,0x1e,0x3e,0x38,0x18,0x9b,0x00,0xb9,0x3b,0xbc,0xae, +0x20,0x1a,0xb2,0x58,0x7e,0x17,0x4e,0x9b,0x69,0x46,0xfb,0x58,0x5f,0x19,0xa7,0x8a,0x84,0x41,0x6f,0xef, +0x87,0x35,0x17,0x94,0x89,0x9a,0x78,0x4d,0xcb,0x13,0xda,0xce,0xe9,0xd0,0x42,0xdc,0xa9,0xe9,0x2c,0x68, +0xa4,0x71,0x79,0x8e,0x02,0xf2,0xd1,0x0e,0xd8,0x61,0x6d,0xb6,0xb5,0x2e,0x65,0x6c,0x68,0x1b,0xc6,0xd8, +0xbd,0x63,0x35,0x72,0xb7,0x17,0x8d,0x8d,0xd2,0x9c,0xf0,0x9d,0x0d,0x8f,0x58,0x29,0x99,0xec,0x20,0x38, +0x35,0xd8,0x6a,0xcc,0x11,0x15,0x4f,0xd8,0xe2,0xcc,0x24,0x88,0xe2,0x68,0x5c,0x1e,0xe7,0x8c,0x85,0x23, +0xe1,0x34,0x8c,0xb5,0x5c,0xc2,0x38,0x8b,0xc0,0xef,0xae,0x20,0x53,0x3c,0x63,0x8c,0x54,0x2f,0x02,0x62, +0x3e,0x3b,0x2b,0xd5,0x39,0x2c,0xb4,0xa4,0x5c,0x2c,0x6b,0xf0,0x27,0x87,0x93,0xda,0xca,0x84,0x60,0x35, +0x35,0x3a,0xc7,0x2e,0x05,0x5c,0xbd,0xa4,0x4c,0x81,0x76,0x33,0x21,0xd5,0x3b,0xf4,0x18,0xdf,0xb7,0x93, +0x2d,0xbf,0xf7,0xc3,0x91,0x80,0xd1,0x76,0x89,0x0a,0x7a,0x2a,0x65,0x5b,0xe5,0x47,0xe4,0x95,0x39,0xc2, +0x27,0xdc,0xab,0x81,0xa9,0x87,0xf6,0x4a,0x51,0x60,0x88,0xef,0x63,0xff,0x5b,0xe5,0x7d,0x78,0x56,0x3c, +0x74,0x8f,0xa7,0x67,0x37,0x67,0x3f,0xcc,0xfa,0x4f,0xbc,0xe9,0x4f,0x4f,0x66,0x0f,0x37,0x7f,0xb2,0x1d, +0x10,0x9f,0xc5,0x61,0x05,0x14,0xdf,0x3d,0x9f,0x05,0x10,0xb3,0x57,0x1b,0x61,0x43,0x51,0x52,0x59,0xed, +0xba,0xf2,0x06,0x91,0xd3,0x89,0x25,0xda,0x6c,0x04,0x7b,0x70,0x9e,0xc8,0x75,0xe5,0xa0,0x37,0x63,0x31, +0x99,0x50,0x99,0xe1,0xa3,0xc9,0x54,0x6c,0x43,0x58,0xc2,0x3a,0x0b,0xbe,0x35,0x78,0x87,0x3e,0x8c,0x2c, +0x7b,0xf9,0x14,0xe9,0x35,0x45,0xd8,0x63,0xb9,0xa6,0x00,0xca,0x4f,0x40,0x9e,0xa7,0x9e,0x1a,0x72,0x2f, +0x68,0x81,0x7c,0x97,0xe6,0x1d,0x1b,0x5d,0x69,0xdc,0x44,0x22,0x27,0x89,0x9b,0x29,0xca,0x28,0x9d,0xa3, +0xce,0x97,0xf1,0x04,0xcb,0x36,0x90,0x98,0xde,0x06,0xf2,0x1d,0x77,0x8c,0x79,0x8c,0x23,0x98,0x3f,0xf6, +0x4b,0xad,0xf6,0xe2,0xd5,0xda,0x81,0xe8,0x98,0xc6,0x3c,0xc4,0xb4,0xff,0xa8,0xb0,0x1b,0x28,0xb2,0x03, +0xcb,0xba,0x14,0x34,0x54,0x15,0xfe,0xb1,0x8e,0x25,0xca,0xf8,0xe6,0xf9,0xcc,0x9b,0xa8,0x0b,0x16,0xb9, +0xab,0xc6,0xb1,0xbe,0x95,0x88,0x3b,0x3c,0xb1,0x91,0xd2,0xf5,0x9e,0x9b,0x10,0x23,0xdb,0x74,0x65,0x41, +0xa8,0x61,0x46,0x3d,0x92,0x9c,0x89,0xde,0x4f,0x7c,0x6b,0x65,0x87,0x87,0x2a,0x88,0x54,0x4d,0x25,0xce, +0x0d,0x34,0x1f,0xc4,0xf5,0x0f,0x64,0x75,0x06,0x4d,0x08,0xd4,0x49,0x75,0xa4,0x0c,0xe1,0x83,0xff,0x71, +0xa2,0x7e,0x79,0xc2,0xd2,0x1a,0xe7,0x4f,0x0c,0x5e,0xaf,0x2b,0xb9,0x7a,0xdb,0xf1,0x33,0x3b,0x58,0x00, +0x4f,0x49,0xff,0x3d,0x2e,0xdc,0x54,0xd9,0x8f,0xfd,0xa2,0xa6,0xb4,0x50,0xae,0xc5,0x06,0x0a,0x4a,0xba, +0xfd,0x2e,0x2d,0x93,0xe5,0x86,0x1d,0x25,0x0e,0xfc,0xa7,0x71,0x78,0xc7,0xfa,0x34,0x4a,0xc2,0x02,0x07, +0x15,0x81,0x05,0xd7,0xec,0x8c,0x09,0x81,0x03,0x7d,0x07,0xa1,0xc1,0xb8,0xbe,0x05,0x42,0x72,0xdf,0x16, +0x98,0x5d,0xc6,0xba,0x86,0x36,0xe7,0x67,0x2f,0xf2,0xee,0xad,0x8d,0xd1,0xe0,0xe1,0x3b,0x79,0x9c,0x8e, +0xe3,0xf6,0xf6,0x26,0x31,0x02,0x38,0xa0,0x64,0xb5,0xbd,0x6d,0xfd,0xf9,0x32,0x2b,0x62,0x1b,0x4d,0xbf, +0x15,0x86,0xd6,0xde,0x8d,0xc1,0xfb,0x43,0x75,0xdc,0xda,0x8a,0xd5,0xc9,0xcc,0xab,0xb6,0xda,0x34,0x54, +0x74,0xa2,0xe3,0x84,0xb1,0x58,0xaa,0x9d,0x14,0xe6,0x9a,0x10,0x4c,0xe3,0x98,0x6d,0x58,0x79,0xb2,0x5b, +0x52,0x25,0xf6,0x3c,0x04,0x74,0x4f,0x34,0x89,0x44,0x90,0x4e,0x9b,0x27,0x94,0xe4,0x4d,0x1f,0x9c,0x5d, +0xc7,0x17,0x63,0x26,0x7b,0x77,0x99,0x91,0x68,0xd5,0x78,0xf9,0xe6,0x7e,0x59,0x69,0xbb,0xea,0x1b,0x36, +0x31,0xd6,0x19,0x8b,0x43,0xa9,0x02,0x9d,0x82,0xe1,0x49,0x07,0x7a,0xb3,0xc6,0x5e,0xe6,0x5e,0xf1,0xd5, +0x7c,0xf6,0x2a,0x48,0x66,0xde,0x9a,0xf5,0x76,0x82,0xed,0x2a,0x50,0xfb,0x08,0xef,0x5c,0xea,0xa2,0x86, +0xa8,0x27,0x03,0x4f,0x74,0x35,0xf1,0x9c,0x98,0x4f,0xb0,0xef,0xd7,0xbb,0x70,0xc0,0x30,0x3f,0x8b,0x45, +0x63,0x14,0x77,0x1d,0x8f,0x76,0xeb,0xea,0xd1,0x26,0x10,0xe2,0x14,0x60,0xbb,0xfc,0x3d,0xa3,0xff,0x52, +0xae,0x5f,0x35,0xe3,0x54,0xd8,0xf9,0xd2,0x7b,0x57,0x83,0x65,0x37,0xa2,0x1f,0x04,0x8d,0x7b,0x3d,0x6f, +0x81,0x7d,0xb3,0xad,0x20,0x7d,0xef,0x3a,0xa4,0xd8,0x5a,0x74,0xdc,0x36,0x84,0xd7,0x06,0xaa,0xf6,0x7e, +0xa8,0xcc,0x24,0xd5,0x2a,0xed,0xaa,0xea,0x0d,0x87,0xdc,0xb4,0xac,0xcf,0x3c,0x93,0x9c,0x17,0xf3,0x2e, +0x34,0xed,0xd6,0x77,0x6c,0xfd,0x9b,0x36,0xa5,0xd0,0x96,0x8d,0x73,0xcd,0x08,0xc0,0xdb,0xca,0xd2,0xdf, +0x95,0xb6,0x69,0xf0,0xa0,0xf2,0xa6,0xa1,0xdd,0xdd,0x88,0x8e,0xfc,0xef,0x4d,0xbf,0xa3,0x8c,0x3f,0xd0, +0x6c,0xbb,0x24,0x6e,0x37,0xb2,0xfa,0x23,0xdd,0xd5,0x34,0xe3,0xc0,0xb7,0x85,0xdc,0x74,0x8e,0xce,0x69, +0x0c,0x6b,0xe9,0xaa,0x97,0x11,0x6c,0xc2,0xb3,0x98,0x48,0x0e,0x59,0x62,0xf6,0xd8,0xee,0x0c,0x6c,0xa6, +0x13,0xa9,0xf5,0x2e,0xdc,0x91,0x1a,0xea,0x5a,0x27,0xb9,0xc8,0xd9,0xe5,0x78,0x62,0x62,0x66,0xe9,0xf3, +0x34,0x70,0x39,0x41,0x19,0x5f,0xaf,0x96,0x51,0x19,0x73,0xd8,0xdc,0xb8,0x0a,0xad,0x05,0xe1,0x56,0x75, +0x60,0xd3,0x76,0x18,0xdb,0xee,0xf3,0x6c,0x4f,0x56,0x5b,0x84,0x82,0x72,0x1d,0xcf,0x2a,0x42,0xc7,0xc2, +0xde,0xb2,0x23,0xac,0x94,0x15,0xd9,0xe8,0x70,0x2f,0xd7,0x6c,0x73,0x1e,0x8b,0xf0,0x27,0xf5,0x00,0x62, +0xd4,0xda,0x70,0x72,0x86,0x9c,0x33,0x4c,0x82,0x0b,0xeb,0x1f,0xcf,0x3e,0x3c,0x81,0x2b,0xe4,0x3e,0x8d, +0xd9,0x52,0xa0,0xbe,0x01,0x24,0x9e,0xff,0x8b,0x25,0xa8,0x49,0xe8,0xe8,0x44,0x74,0x23,0xb0,0xd7,0x7e, +0x33,0x6a,0x8b,0xa7,0xc9,0xbd,0xdf,0x80,0x21,0xf1,0x53,0x8d,0x93,0xe9,0x1f,0x5c,0xe2,0x78,0x3b,0xa1, +0xed,0xed,0x9c,0x12,0x17,0x35,0x23,0xdb,0x38,0xec,0xda,0x23,0x5d,0x39,0x99,0xab,0xe8,0xa0,0xea,0xd8, +0x35,0x11,0x4d,0xe4,0xb4,0x99,0xc2,0x25,0x61,0x70,0xe8,0x2f,0xc3,0xc6,0x89,0x97,0xc0,0x22,0x36,0x1e, +0x66,0x44,0x4e,0x81,0x6b,0x40,0x04,0x4c,0x0d,0x98,0x37,0xc6,0x17,0xea,0xc4,0x89,0x4c,0x74,0xad,0x7e, +0x7f,0x7d,0x6c,0x24,0x70,0x5e,0x36,0x5d,0x1b,0xa4,0x31,0x48,0xff,0x52,0x10,0x4d,0xa1,0x8e,0x1d,0x8f, +0x68,0x91,0x6f,0xd2,0xe7,0xd1,0xb2,0x88,0x19,0x0e,0x5b,0x7f,0x07,0x9b,0xc7,0x43,0x20,0x12,0x5c,0xc7, +0xd7,0x59,0xfe,0x71,0xb3,0x71,0xf9,0x01,0xb1,0x03,0xbd,0x43,0xa6,0x76,0xb2,0x30,0x05,0xbc,0x1e,0x07, +0x09,0x98,0x87,0x77,0xb5,0x6d,0xb9,0x32,0x57,0x50,0xf0,0x83,0x65,0x2d,0x6f,0x6a,0x64,0xa4,0x0f,0xab, +0x4a,0x6f,0xbd,0x07,0x82,0xf2,0xae,0x33,0x3c,0x62,0xca,0xcf,0x6b,0x11,0x01,0x27,0x7a,0x74,0xf7,0xf7, +0xe7,0x50,0xc5,0xd2,0x23,0x18,0x91,0xa9,0x5c,0x03,0xd6,0x07,0x6b,0x36,0xb0,0x3a,0xc7,0x4d,0x74,0x0e, +0x98,0x5f,0xe6,0xc0,0x24,0xf3,0xb6,0x16,0x0e,0xbc,0xaf,0xea,0xba,0xd4,0xb3,0x02,0xe6,0xbf,0xc0,0x0a, +0xee,0x68,0x9a,0xae,0x68,0x85,0x43,0xbf,0x83,0x17,0x1f,0xbb,0x1c,0xaf,0x49,0x05,0x34,0xa0,0xd6,0xc0, +0xc8,0x01,0x07,0x3c,0x0d,0x8d,0x31,0xe7,0x86,0x60,0x32,0x3d,0xe6,0x00,0x64,0x83,0xc1,0x56,0x17,0xde, +0xa4,0x9c,0xcc,0x51,0x6c,0xe5,0x17,0xfb,0x19,0x53,0x0b,0x59,0x65,0xee,0xd0,0x54,0xc5,0xd6,0x86,0x83, +0xf5,0x1a,0x2a,0x7f,0x25,0x15,0xea,0x0a,0x0b,0x15,0x46,0x22,0xb5,0x67,0x8b,0xf1,0x5a,0xea,0x8e,0x71, +0xee,0x65,0x5b,0x1f,0x11,0xb1,0x77,0x67,0x44,0xfc,0x0c,0x64,0xfd,0x92,0x9f,0x2e,0x1e,0x9f,0x74,0x66, +0xd7,0x4b,0x58,0xe7,0xc8,0x21,0x5a,0x1b,0x56,0x41,0x3a,0x5b,0x9e,0x90,0x22,0x77,0x4f,0x61,0xb4,0xa3, +0xb4,0xff,0x13,0x6d,0x05,0x40,0x53,0x60,0x56,0xcd,0x32,0x9f,0x0a,0xb7,0x06,0x15,0x79,0x77,0xd4,0x75, +0x3e,0xd4,0x85,0x36,0x03,0x36,0x59,0xdf,0x75,0xd6,0x37,0xdf,0x1a,0xa0,0xb2,0x79,0x2d,0x16,0x8e,0x8e, +0xab,0xdc,0x61,0xd5,0x30,0x9d,0x3a,0x12,0xa1,0xd6,0xc1,0x59,0x22,0xd1,0x54,0x11,0x77,0xac,0xda,0x5b, +0x5c,0x47,0x16,0x9f,0xe3,0xed,0x7a,0x7c,0x34,0xf3,0xa7,0x8e,0x8a,0x67,0x4b,0xd9,0x20,0xfc,0x6a,0x33, +0x0b,0x6c,0x1b,0x7b,0x3b,0xf2,0xa9,0xbf,0x1b,0xf9,0x3a,0xab,0x85,0x23,0xf9,0x32,0x00,0xbb,0xef,0x20, +0x66,0xeb,0x7f,0x9e,0xed,0xa1,0xaf,0x72,0x42,0xb6,0xf0,0x9e,0x70,0xe0,0x26,0xca,0x27,0x66,0x12,0xaa, +0xf8,0x71,0xed,0xb1,0xc8,0x89,0x26,0xe3,0xb0,0xb0,0x5d,0xd3,0x58,0x62,0xce,0x56,0xc3,0x23,0x11,0x66, +0x5b,0xc3,0xe5,0xb0,0x07,0x8f,0xd3,0x79,0x38,0x0e,0xcb,0xab,0x38,0x55,0xd0,0x8b,0x38,0xf3,0x93,0x55, +0xad,0x16,0xc2,0x65,0x98,0x1c,0xc7,0xd5,0xa2,0x37,0x91,0xb2,0xed,0x11,0xd5,0x9b,0x41,0xea,0xef,0x38, +0xfe,0x6c,0x4e,0x6e,0x9a,0x4f,0x3f,0x9f,0x81,0x6f,0x55,0x57,0xe3,0x6c,0x0a,0x46,0x76,0xe6,0xb6,0xca, +0x07,0x96,0x6e,0x77,0x04,0xb1,0x71,0xac,0xd8,0xde,0x2a,0x5b,0x1d,0x97,0x1a,0x5b,0xa3,0x0e,0x51,0xed, +0x55,0x71,0x7b,0x4b,0x15,0x0f,0x59,0x05,0xec,0x2d,0x75,0x18,0x64,0xd5,0x79,0xa5,0x0a,0x7f,0x4c,0xe4, +0xf9,0x14,0x71,0x55,0xfb,0x0e,0xd6,0x81,0x33,0x93,0x82,0x13,0x8e,0xd3,0x52,0x15,0x0f,0xa8,0x67,0x04, +0xea,0x60,0xb1,0x6e,0x55,0xda,0xd6,0x47,0xaf,0xda,0x76,0xb1,0x82,0x5d,0xab,0x77,0xf8,0xcc,0x35,0x36, +0xbb,0x4d,0xe3,0x2d,0x69,0x72,0x21,0x01,0xb4,0xe6,0xa1,0xb5,0xab,0xb6,0x43,0x81,0x5d,0x30,0xff,0xe5, +0x96,0xc7,0x91,0xa7,0x7c,0x01,0x73,0xd5,0x4b,0xf4,0x29,0xea,0x05,0xbe,0xc9,0x54,0xca,0xab,0x3c,0x82, +0x40,0x47,0x2b,0xaf,0xa0,0xd3,0x2b,0xb1,0xc8,0x81,0x4b,0xfe,0xc5,0x80,0xfb,0x62,0xcd,0x7a,0x3f,0x6f, +0x7c,0xc1,0x68,0x3a,0x7f,0x34,0xde,0x10,0xc6,0x91,0x27,0x53,0x23,0x66,0xc9,0x85,0x37,0x49,0x26,0x17, +0xda,0x2f,0x2d,0x73,0x23,0xd8,0x08,0x53,0xcb,0xd5,0xe5,0x12,0xa4,0x4b,0xe0,0x46,0xfd,0xbe,0x7f,0x7f, +0x22,0xf3,0x34,0xb5,0x02,0x5a,0x7b,0xf8,0x36,0x97,0x88,0x95,0x6e,0xa1,0x84,0xcd,0xc0,0x3e,0x25,0xbe, +0xd7,0x77,0x69,0x73,0x4c,0xed,0x28,0xd7,0x1e,0xf7,0x0b,0x68,0xb6,0x15,0xec,0x9a,0xed,0x79,0x0e,0x17, +0xba,0x0b,0x57,0xe3,0xe8,0xc7,0x3c,0x93,0xf5,0x0c,0xa7,0x4d,0x6c,0x1e,0xb3,0x15,0x11,0xa2,0x4f,0xf3, +0x7c,0xeb,0x7e,0x45,0x55,0x5f,0x21,0x64,0xf4,0xfc,0xd7,0xd3,0x3c,0x9a,0x83,0x11,0xec,0x1f,0x3e,0x09, +0x11,0x61,0x0d,0x55,0x5c,0x76,0x54,0x31,0xb5,0x83,0x6d,0xab,0xca,0x8d,0xcb,0xc9,0x0a,0x9a,0x05,0xbb, +0x18,0x62,0xd4,0x98,0x26,0x93,0x0a,0xb8,0x76,0x29,0xe1,0xae,0x74,0xae,0xf8,0x3e,0xc4,0x1c,0x13,0x3d, +0x5b,0x97,0xee,0x0a,0xb9,0x63,0xe6,0x44,0xe1,0xe8,0xde,0x85,0x8c,0x10,0x50,0x34,0xf5,0xa7,0x8f,0x66, +0xcc,0xef,0x65,0x2e,0xa2,0xd2,0xd6,0x47,0x35,0xa1,0x51,0x0d,0xd6,0x7e,0x5c,0x1b,0x0b,0x26,0xa9,0xee, +0xfb,0xaa,0xf4,0x88,0x7b,0x5b,0x73,0xc2,0xa3,0x7b,0x13,0xe6,0xde,0x24,0x0f,0x96,0xd0,0xc5,0xd9,0x8b, +0x4a,0x5d,0xde,0x13,0xa0,0x6c,0x52,0x1d,0x39,0x1c,0x37,0x3a,0xa1,0xb1,0x46,0x40,0xe0,0x71,0x83,0x58, +0x49,0x1b,0x44,0x8a,0xf4,0x4a,0x09,0x9b,0x69,0x5a,0x7a,0xd3,0xc7,0xb3,0x71,0x32,0x2d,0xb1,0x17,0x11, +0x35,0x49,0x75,0xf4,0x0b,0x84,0x23,0x41,0x65,0xed,0x4d,0x38,0xa4,0xad,0x35,0x9d,0x3e,0x1a,0xc4,0x33, +0xfa,0x4e,0xbb,0xf9,0xfb,0xdc,0x73,0x74,0x8f,0x43,0xdd,0xf3,0xe5,0xab,0x12,0x6d,0xc5,0xa1,0x09,0x1d, +0x3e,0x84,0x80,0xb3,0xb0,0x63,0x37,0xe7,0x37,0xb5,0xfd,0x06,0x0e,0x0a,0x4a,0xdc,0x15,0x74,0x9f,0xc4, +0xf5,0x8f,0xa8,0xb6,0xfa,0xe4,0x86,0x5a,0xcc,0xf4,0x5d,0xe6,0x89,0x4c,0x91,0xd7,0x57,0x86,0x78,0x4b, +0x44,0xa8,0xdc,0x5c,0xc5,0x5d,0x06,0x5c,0xad,0xe0,0x81,0x88,0x5d,0x9d,0x87,0x3a,0x76,0x1e,0x9d,0x55, +0xed,0xb8,0x41,0xd4,0xc7,0xf6,0x44,0xf2,0x6c,0x9c,0xda,0x1d,0x06,0xaa,0x60,0x91,0x64,0x4b,0xc5,0x55, +0xb3,0xd0,0x27,0x87,0x93,0x76,0x29,0x41,0xea,0x0f,0x06,0x25,0xa8,0x5b,0x3b,0x72,0x3d,0x76,0x51,0x5a, +0x34,0x90,0xb7,0x1e,0x87,0x60,0x7b,0xe6,0xd8,0x41,0xd4,0xc9,0x08,0xc2,0x5a,0xa7,0xf6,0x33,0xb5,0xd8, +0xa0,0xf7,0xf7,0xcd,0xe1,0xcb,0x4e,0x20,0x7c,0xfa,0x02,0xed,0xb6,0x31,0xcb,0x39,0x8a,0x33,0xfe,0xf2, +0xce,0x56,0x05,0xba,0xc9,0xe4,0xd8,0x54,0x2e,0x89,0x6c,0xa6,0x31,0xe7,0xd4,0x3e,0x8a,0x34,0x25,0x55, +0x56,0xd6,0xd6,0x34,0x56,0x3c,0xd5,0x2b,0x16,0x36,0x22,0xf6,0xda,0xe6,0x25,0x71,0x9a,0x79,0x4a,0x17, +0xef,0xa2,0xf4,0x32,0xde,0xbc,0x43,0x3f,0xc6,0x44,0x3b,0x6c,0xc4,0x65,0x73,0xc3,0x6e,0xff,0xdf,0xbd, +0x7b,0xe9,0xf1,0x9e,0x2d,0xea,0xa1,0xee,0x1d,0x28,0xb4,0x8e,0x9c,0x14,0x28,0x1f,0x10,0x53,0x67,0xe2, +0x7a,0xa9,0x2e,0x87,0x37,0x51,0x8e,0x00,0x15,0xfb,0xfb,0xaf,0x14,0x1f,0x48,0x27,0x22,0x8c,0xfa,0x9a, +0x69,0x5c,0x15,0xb7,0xd0,0x14,0xb5,0x67,0x8a,0x82,0x29,0x6e,0x49,0x1c,0x51,0x51,0x44,0x97,0xf0,0x9e, +0xe5,0xdd,0x88,0xf9,0xfe,0xcb,0x58,0x64,0xb1,0x5f,0xeb,0xa4,0xa1,0x4d,0x1e,0xd4,0xb6,0x23,0x7b,0xf7, +0xe5,0x93,0xa9,0xa4,0xd3,0x94,0xbb,0xe6,0x45,0x5c,0x9f,0x4e,0x4a,0x8e,0xca,0x19,0x77,0x4d,0xac,0x17, +0x72,0xf0,0xd0,0x93,0xa9,0x22,0x75,0x66,0xb5,0xcd,0xac,0x55,0x29,0x97,0xa1,0x23,0x64,0x05,0x59,0x44, +0xaa,0x09,0xbd,0x78,0xe8,0x73,0xfa,0x1f,0xa2,0xa4,0x0c,0xd4,0x75,0x6d,0xa5,0xb0,0xd7,0x7d,0x6f,0x34, +0x19,0x0c,0x74,0xd6,0x9c,0x94,0x27,0x0f,0x67,0x01,0x9b,0xa4,0xea,0x8e,0x63,0xbc,0xa8,0x88,0xc6,0xf5, +0x4f,0x9e,0x8c,0x36,0x9b,0x17,0x71,0x6d,0x3e,0xa7,0xb1,0x3f,0xbd,0x84,0xd8,0x56,0x09,0xcd,0x38,0x2d, +0xb7,0x2f,0x54,0xed,0x44,0xb0,0xc2,0xeb,0x15,0x02,0xd0,0xb0,0xef,0x90,0x4a,0xf2,0x1e,0x53,0x18,0x80, +0x81,0x59,0xb4,0x50,0x4c,0x5e,0xed,0x15,0xc0,0xef,0x5b,0x18,0x14,0x74,0xff,0x7e,0x9e,0x67,0xcb,0xe5, +0xa4,0x36,0x34,0xba,0x58,0x3a,0x85,0xe8,0x9b,0x36,0x84,0xdc,0xb3,0x37,0xaf,0x95,0xf5,0xf7,0x2b,0x2a, +0x0d,0xd0,0x24,0x17,0x8c,0xd9,0xd2,0x4a,0x28,0xd0,0x71,0x40,0x87,0xc7,0xb8,0x3e,0x6f,0x6a,0x8b,0x75, +0x20,0x53,0x4d,0xf4,0x74,0x60,0xf9,0x43,0x71,0x6c,0x45,0x41,0x0a,0x6d,0xd6,0x95,0x88,0x1e,0x08,0x01, +0xd8,0xf6,0x4d,0xa2,0x88,0x3f,0x97,0xa8,0xde,0x05,0xed,0xc2,0x05,0xd4,0x60,0x9c,0xb9,0x71,0x4e,0xa9, +0xc5,0xee,0x4c,0x54,0xd4,0xfa,0xda,0xa9,0xc3,0x91,0x4c,0x19,0x67,0x9d,0xe5,0xd0,0x26,0xb0,0x20,0xec, +0x60,0x04,0xfe,0x9c,0xba,0x64,0x49,0x1b,0x62,0x5b,0x91,0xa5,0xe6,0xe2,0xd2,0x16,0x04,0xa7,0x0c,0xbe, +0xa2,0xb4,0x30,0x26,0x24,0x41,0xc9,0x7e,0x01,0xd4,0xfa,0x88,0x0e,0xb9,0x5c,0x87,0x2e,0x2c,0x80,0xbb, +0xaf,0x5f,0x59,0x61,0x08,0x92,0x49,0x1c,0x2c,0x27,0xba,0x22,0x5e,0xb0,0x9e,0x88,0x93,0xa5,0x0f,0x97, +0x8d,0xad,0xff,0xa6,0xcb,0x4d,0xbc,0xa1,0x8e,0x15,0x4f,0x66,0xfb,0xbe,0xd7,0xb7,0x94,0xb5,0xe3,0xd5, +0x10,0xa1,0xde,0x0e,0x7d,0xdb,0x94,0x51,0x9c,0x85,0xbb,0xa4,0xb4,0x53,0x89,0xbb,0x2b,0xc1,0x4d,0x1b, +0xfe,0x88,0x77,0xa8,0x10,0x0b,0x96,0x5c,0x1b,0xfa,0xa4,0xfe,0x49,0x58,0x06,0x4a,0x42,0x2c,0x8e,0x84, +0x95,0x33,0x89,0x6f,0xa7,0xf3,0x95,0x05,0x5f,0x09,0xe9,0xde,0x45,0x72,0xb9,0xce,0x99,0x47,0x67,0x35, +0x2d,0x4c,0x28,0xfc,0x22,0x2e,0x5b,0x92,0x49,0xed,0x6a,0x22,0x3a,0x3a,0x34,0x41,0x03,0x7c,0xb5,0xa2, +0xed,0x79,0xc9,0x14,0x0a,0x13,0x1d,0xe5,0x92,0xf6,0xa7,0x19,0xcd,0x35,0xe3,0x58,0xad,0x94,0x66,0x8d, +0x44,0xb9,0x57,0x0f,0x89,0x98,0x34,0x43,0x45,0x5b,0x82,0x78,0x99,0x6e,0x50,0xc4,0x4f,0x6a,0xd5,0x09, +0x1a,0xfd,0x01,0x06,0xa8,0xf6,0xa0,0x55,0x2f,0xe2,0x01,0x39,0xac,0xf8,0x2e,0x41,0x6c,0x55,0xd2,0x66, +0x53,0x76,0xc8,0x0b,0xe9,0x99,0x49,0x92,0x4e,0x8c,0xe8,0x1f,0x95,0x0d,0x44,0x13,0x50,0xc4,0x2a,0x8e, +0x9d,0xe7,0x57,0xea,0xb5,0x49,0x1a,0x00,0x8e,0xa1,0x29,0xfa,0xa9,0xa9,0x8c,0x9a,0xd3,0xa1,0xb6,0xcc, +0x98,0x2b,0x31,0xb7,0xf4,0x55,0x3d,0x12,0x2f,0xc8,0xc1,0xb0,0x64,0x91,0xa8,0xdd,0x62,0xd4,0x29,0x6c, +0x74,0x81,0x2f,0xca,0xd4,0xbd,0x7c,0x32,0x2d,0x67,0x81,0xc2,0xe3,0x70,0x7f,0x8b,0xc5,0x98,0xcf,0xd6, +0x9c,0x55,0x27,0xb2,0x0a,0xd2,0x95,0x4f,0x61,0x3d,0x39,0xdb,0xba,0x76,0x2f,0xf1,0xc2,0xb7,0x62,0xb5, +0xba,0x0c,0x52,0x74,0xdf,0xa4,0x55,0x64,0x58,0x15,0xf9,0xcb,0x7e,0x0b,0x9e,0xe2,0x2a,0x2a,0x9e,0x21, +0xe8,0xfb,0x1f,0x5e,0x32,0x55,0xc7,0xd0,0xde,0xdc,0xaa,0x50,0x09,0xaa,0x06,0xdf,0xbf,0x8d,0x95,0xd9, +0xf0,0x3b,0x7d,0xf1,0x5a,0xab,0xde,0xef,0x44,0xef,0xfe,0xf0,0x6c,0xbb,0x39,0x9b,0xea,0xeb,0x19,0x94, +0xee,0x2f,0x21,0xb1,0x7d,0x3a,0xf8,0xd7,0x4c,0xc4,0xb4,0x96,0x0a,0xb2,0x55,0x47,0x55,0x9b,0x77,0x1c, +0x2d,0x1e,0x6f,0x5d,0xf4,0xea,0x5b,0xfb,0x76,0x2b,0xe1,0xec,0x77,0xcc,0x3e,0xfa,0x52,0xa6,0xa7,0x7a, +0xae,0x67,0xcc,0xb3,0xe6,0x37,0xde,0xdd,0x3b,0x1d,0x74,0x4c,0x21,0x7d,0xfc,0x7c,0x5f,0xbe,0x6f,0x5b, +0xf9,0xfe,0xbc,0x33,0xe3,0xb7,0xf5,0x8c,0xe5,0xe8,0xb4,0x74,0xaf,0xad,0x72,0x1a,0xc0,0x8c,0xa2,0x81, +0x43,0x7c,0x0e,0xb8,0xf7,0x56,0x56,0x73,0xd5,0x7c,0x16,0x78,0x40,0x90,0x99,0x95,0x98,0x9d,0x8f,0x91, +0x77,0xac,0x0a,0x07,0x8d,0x7d,0xc8,0xb4,0x64,0xa5,0xa8,0xec,0xbd,0x55,0xaf,0x7c,0x47,0xf5,0x25,0xcc, +0xc4,0x0a,0xc7,0x53,0x11,0xfb,0x52,0x13,0xf0,0x45,0x26,0x6c,0xc4,0xe4,0xa6,0x9b,0x87,0xb8,0x60,0xa2, +0xcc,0x1f,0xb1,0xe5,0x8e,0x71,0x87,0x47,0x33,0x06,0x8e,0xe8,0x06,0xea,0xfb,0x92,0x12,0xf7,0x3d,0xa6, +0xad,0xf1,0x4a,0x62,0xdc,0x40,0x79,0x4f,0xc7,0xc8,0x5b,0x3e,0xd9,0x5b,0x75,0x80,0x01,0x81,0x51,0xe7, +0xab,0x8b,0x36,0xab,0x2f,0x7b,0x05,0xb3,0x4c,0x16,0xb9,0xf6,0x4e,0xb2,0xd4,0xe1,0xe5,0xbd,0xe0,0x79, +0xdc,0x8c,0x1a,0xaf,0x5d,0xaf,0x24,0xfa,0x43,0xb5,0xf2,0x14,0xd2,0xa5,0xee,0x33,0xfa,0xdc,0xda,0x6f, +0x6a,0x61,0x24,0xd3,0xf0,0x6a,0xe7,0x7b,0x39,0xd1,0x3f,0x5d,0x37,0x0e,0x53,0xbf,0x15,0x97,0xba,0xd2, +0x6f,0x33,0x19,0xf2,0x06,0x3d,0xd1,0x3d,0x65,0x1b,0xa1,0xe6,0xdb,0x45,0xa9,0x39,0x67,0x7a,0x42,0x2b, +0x3a,0xd5,0xac,0xfb,0x6d,0x1d,0xaf,0xe3,0xee,0x33,0x0a,0x4d,0xac,0xec,0x5d,0x42,0x0e,0xf5,0x73,0x71, +0x0b,0x2f,0x71,0xfe,0x08,0xe8,0x24,0x6a,0xf6,0xa0,0x15,0x10,0xc8,0x33,0x16,0x58,0x2b,0x94,0x39,0x27, +0xb3,0x96,0x49,0xcd,0xf4,0x81,0xe8,0x88,0x20,0xaf,0x34,0x0c,0x39,0x36,0x4b,0x5a,0xcb,0x71,0xbb,0x5e, +0x44,0x83,0x87,0xaa,0x0a,0x0a,0x4a,0xe7,0x92,0x01,0xe6,0xd6,0xb2,0xa0,0xac,0x60,0x7f,0x3e,0xa2,0x93, +0x18,0x5b,0x7b,0x24,0xfb,0x99,0xd3,0x81,0xfd,0x28,0x24,0x71,0x64,0x73,0xb7,0x97,0x30,0xd7,0xac,0x72, +0xda,0x8e,0x61,0xe8,0xa9,0xc5,0xbc,0x70,0x30,0xe7,0x45,0x54,0x65,0x99,0x0f,0x06,0x62,0x46,0x82,0xba, +0x84,0xca,0x30,0x4f,0x03,0x41,0xd9,0xdf,0x02,0x2a,0x9f,0xf7,0xe2,0x8c,0x95,0x37,0xc4,0xee,0x2a,0x5a, +0x2d,0x22,0x06,0x17,0x46,0x3d,0xb4,0x92,0xb1,0x98,0x59,0x09,0xc0,0x7c,0x31,0x64,0x08,0x56,0x65,0xbb, +0x23,0x39,0xab,0x01,0xe0,0x14,0xce,0xb8,0xda,0x8a,0x64,0x28,0x52,0xd9,0x1a,0x4d,0x87,0xa7,0xfe,0x9d, +0x28,0x19,0xee,0x91,0xfc,0x36,0x05,0x07,0xf6,0x5e,0x35,0x2d,0xcd,0x80,0xa7,0x33,0x89,0x1c,0xd7,0xda, +0xbb,0xba,0x46,0x4b,0x2a,0x7b,0xa4,0x15,0x88,0x1d,0x06,0x1a,0xae,0xc4,0x10,0x46,0x2f,0xfa,0x29,0xfa, +0xb4,0x39,0xfd,0x8f,0xd3,0x89,0x19,0x63,0xbd,0xff,0x19,0x34,0x55,0x43,0xb5,0x04,0x9d,0x53,0xbf,0x31, +0x45,0xcc,0x6a,0x1b,0x37,0xa6,0x83,0x5a,0x18,0xbe,0x1a,0xcb,0x58,0xcc,0x7c,0xf5,0x08,0x62,0x4d,0xb3, +0x01,0x84,0x35,0x47,0xaa,0xa5,0xd4,0x31,0x4f,0xef,0x5f,0x8f,0xdd,0xb9,0xcc,0x97,0x71,0x94,0xff,0xe3, +0xde,0x8c,0xd4,0xec,0x94,0xe9,0x0f,0x9f,0xde,0x2e,0x51,0x93,0x4d,0xf4,0x1c,0xfa,0x49,0x43,0xe0,0x21, +0x47,0x08,0xcd,0x7c,0xdb,0x7c,0xa6,0xb0,0xd7,0xc1,0x60,0x40,0xcb,0x2f,0xa9,0xb1,0x7a,0x99,0x8f,0x70, +0x6f,0x5b,0x26,0x59,0xee,0x19,0x42,0x19,0x11,0x76,0x47,0x50,0x2b,0x54,0x82,0x10,0xea,0x0d,0x02,0x91, +0x08,0xfd,0xb8,0x36,0x6f,0x15,0xa0,0x2f,0x4f,0x4d,0x1c,0x16,0xfd,0xbe,0xaf,0xee,0x78,0x32,0x16,0x15, +0x7b,0x51,0xb8,0xb6,0xa0,0xa8,0x34,0xe2,0x89,0x1f,0x38,0x6c,0xc0,0x60,0x36,0x01,0x9d,0xb1,0x78,0x78, +0x36,0xdc,0x78,0x67,0x8b,0x3e,0xdd,0x4c,0xe3,0xaf,0x67,0xfc,0x82,0x6e,0x37,0xde,0x81,0x8a,0xc8,0xe9, +0x3f,0x68,0x04,0xb4,0xd0,0x21,0x1c,0xbc,0x70,0xe3,0xb9,0x4e,0xff,0x07,0x0e,0x27,0x02,0x43,0xd9,0x3f, +0xcf,0x1e,0x9a,0xb0,0x0c,0x5f,0xc5,0xe1,0xd4,0x39,0xcd,0x56,0x74,0xfb,0x0e,0x56,0xf0,0xf4,0xfb,0x55, +0x56,0x96,0xd9,0x35,0x5d,0xbc,0x8a,0x2f,0x4a,0x67,0xe6,0xff,0xbc,0x03,0xb7,0x3f,0xc6,0x76,0x05,0xab, +0x05,0xa8,0x7a,0x98,0xbb,0x29,0xca,0x8f,0x4b,0x06,0xd3,0xe7,0xa8,0x2e,0x1b,0xa7,0xe3,0x29,0xcf,0x34, +0x63,0x22,0xd5,0x00,0x14,0xf3,0xc1,0xb6,0x98,0xfc,0x90,0x90,0x57,0xb8,0xa3,0xbe,0x85,0x7e,0xf7,0xf7, +0x36,0x03,0x6b,0x07,0x22,0xbf,0x93,0xa1,0xcc,0x84,0x73,0x88,0x10,0x9d,0x4f,0x55,0x00,0x51,0xce,0xab, +0x4b,0xe2,0x20,0x40,0x29,0xd3,0xa6,0xa7,0x11,0xf3,0x79,0x67,0xf6,0xec,0xaf,0xad,0xd4,0xc8,0xc8,0xe2, +0x37,0x7e,0x8c,0x51,0x50,0x7d,0x8b,0x28,0xae,0xb2,0x9b,0x0e,0x05,0x91,0x52,0x97,0xf0,0x01,0x77,0x95, +0x2c,0xba,0xf4,0x4b,0x92,0x04,0x1a,0x8b,0xec,0xf2,0x72,0xd9,0xb5,0x46,0x9c,0x73,0x89,0xc1,0x6d,0x93, +0x05,0x8a,0x30,0x40,0xb1,0xae,0xb2,0x19,0x44,0xfe,0xfa,0xba,0xb9,0x32,0x7f,0x96,0x15,0xc9,0x56,0xa5, +0x7c,0xa1,0xbf,0x34,0xf7,0xf2,0xf5,0xd6,0x4c,0xbf,0xef,0x14,0x89,0xab,0xfd,0xf9,0x36,0xec,0xe1,0xc7, +0xf6,0xd2,0xdf,0xd3,0xab,0xba,0xcd,0x75,0xdd,0x30,0xc1,0xa3,0x34,0xdf,0xe0,0xf3,0x07,0x9b,0xb3,0x03, +0xca,0xe2,0x97,0xe8,0x43,0xb4,0x89,0xe7,0xd7,0x91,0x57,0xcc,0xf3,0x64,0x55,0xd2,0xeb,0x7f,0x52,0x17, +0x8a,0x5f,0x70,0x30,0x3d,0xf4,0x1d,0x0d,0x6e,0xab,0xe3,0xfb,0x84,0x9f,0xe9,0xab,0xcf,0xe0,0xd8,0x51, +0xc1,0xda,0xc2,0x60,0x38,0x8e,0x16,0xf2,0x11,0x7b,0xb1,0xc8,0x7b,0x75,0x39,0x23,0x4e,0x75,0x19,0x4c, +0x8f,0xcc,0xcb,0x63,0xba,0xbf,0xcc,0xb3,0xf5,0x4a,0x92,0x99,0x3b,0xeb,0x8b,0x32,0xaf,0x7d,0x50,0x9e, +0x67,0x8b,0x8f,0x2a,0x53,0xbe,0xb4,0x93,0x52,0xc1,0x8f,0x9a,0x49,0x8f,0xcb,0x5c,0x25,0xcf,0x9f,0x74, +0x7c,0xf3,0xb3,0x72,0x95,0x08,0xa6,0x23,0xa0,0x39,0x38,0xce,0x6c,0x3b,0xfe,0x27,0x4d,0xfc,0x55,0xc9, +0x35,0x09,0xe5,0x9a,0x3a,0x82,0xfa,0x64,0xc8,0x5f,0xe3,0x51,0x79,0x91,0x65,0x25,0x2e,0x74,0x8d,0xf9, +0x3a,0x12,0x81,0xde,0x3f,0x59,0x0a,0x15,0x2d,0xf8,0x8b,0x2b,0xbe,0x5d,0xf0,0x98,0xfd,0x03,0x03,0xb3, +0xd9,0xff,0xd3,0xe4,0xec,0xa6,0x3f,0x3e,0x18,0xf7,0x5a,0x6a,0xbc,0x34,0x56,0x6e,0x37,0x7a,0xc9,0x3d, +0xcf,0xa3,0x4b,0xf6,0xbf,0x01,0x7f,0x57,0xc7,0xfc,0x35,0x69,0x8d,0x8b,0xce,0x22,0xf9,0xe0,0xb0,0x7b, +0x5c,0xfb,0x95,0x86,0x15,0x4e,0xbb,0x61,0x85,0x79,0xee,0x60,0x4f,0x6c,0xbc,0xd6,0xc8,0xca,0xbe,0xb9, +0x6a,0xa7,0x51,0x50,0xc3,0x25,0x94,0xf5,0xf5,0x0a,0x82,0xfe,0x10,0x3f,0xf3,0x93,0x25,0x6d,0x1a,0xf0, +0x00,0xc4,0x2f,0x3b,0x80,0xd0,0x8a,0x6b,0xdc,0x19,0xfc,0x17,0xed,0x9a,0xee,0x97,0x35,0xcf,0x1b,0x1d, +0x08,0xe6,0xc9,0x2d,0x8d,0x9e,0xbe,0x76,0x50,0x44,0x9a,0x71,0xfe,0x27,0xf2,0x59,0xd8,0xeb,0x35,0x0b, +0xaa,0xb2,0xae,0xf9,0xc5,0xb8,0xb2,0x92,0xfe,0xc6,0xfd,0xde,0x8c,0x2c,0xf1,0x77,0x2c,0x90,0x5f,0xe3, +0x8f,0x07,0xfe,0xbf,0xd4,0x4a,0xbb,0xce,0xd6,0x45,0xbc,0x59,0x65,0x09,0x84,0xd1,0x1c,0x14,0x8b,0x6a, +0x41,0x69,0xd7,0x9b,0x05,0x8d,0x12,0xfd,0xc9,0x56,0xde,0x66,0x4e,0x4c,0xc6,0xaf,0x07,0x7e,0x5c,0xe2, +0x9b,0xe9,0x4f,0x43,0xda,0xcb,0x71,0x3e,0x0c,0xdd,0x21,0xa2,0xf3,0xb0,0x60,0x1a,0x8e,0xcb,0x65,0x78, +0x77,0xb9,0xcc,0xce,0xa3,0x25,0x80,0xe3,0x9a,0x86,0x8a,0x35,0xb4,0xa2,0xca,0xcd,0xb5,0x42,0x0b,0xf2, +0x3f,0x18,0xd2,0xd7,0x13,0x60,0x1f,0x66,0x96,0x88,0x1f,0x05,0x26,0x5d,0x2e,0x36,0x37,0x3e,0xc0,0xec, +0xd5,0x13,0x40,0x8b,0x18,0xbf,0x19,0x26,0x1e,0x77,0x99,0x88,0xfe,0x0d,0x5a,0x21,0x1a,0xe3,0xcb,0x75, +0xb2,0x80,0xe5,0x04,0x5f,0x60,0xaf,0xc7,0x6f,0xbf,0xef,0xf9,0xee,0x3a,0xfc,0x20,0x4d,0x28,0x20,0x0c, +0xac,0xee,0x18,0xdb,0xc5,0x8d,0xe8,0x5e,0x0a,0x15,0x51,0xa1,0xbe,0xab,0x49,0xb9,0xd5,0xb6,0xd9,0x81, +0x93,0x75,0x29,0xda,0x6a,0xce,0x71,0x48,0x53,0xec,0xf2,0x32,0xce,0x39,0xec,0xb1,0xc4,0x6f,0x9e,0x98, +0x77,0x38,0x73,0xd8,0xdd,0x44,0x1f,0x10,0x96,0x16,0x44,0xc1,0xdd,0x63,0xc9,0x30,0xd7,0x40,0x04,0xa6, +0x2d,0x0d,0xa1,0x25,0xee,0x2f,0x2b,0x71,0xc8,0x12,0xa4,0x42,0x11,0xc6,0xa5,0x58,0xbb,0x97,0xd3,0xe5, +0xcc,0x53,0x00,0x3b,0x97,0x61,0x01,0x6b,0xf3,0xab,0xd0,0x2d,0xa6,0x47,0x0a,0x0a,0x4f,0xb9,0xe4,0x0d, +0xb5,0x4f,0x1e,0x4d,0x72,0x46,0xc2,0x31,0x35,0x63,0x9f,0xa6,0x68,0x39,0x5d,0xcc,0x60,0xb6,0x47,0xb9, +0xb8,0xd0,0xee,0x82,0x12,0xbf,0xa4,0x15,0x09,0xbe,0x37,0xb8,0x18,0x9e,0x53,0xdf,0x2b,0x3c,0x9d,0x85, +0xbf,0xfb,0xe3,0x79,0x68,0xf1,0x4a,0xec,0xa6,0xbb,0xf0,0x33,0xea,0x15,0xce,0xe5,0x52,0x64,0x0e,0xb9, +0xaf,0x06,0x39,0x48,0x7d,0x0c,0x52,0x20,0x63,0xe6,0xeb,0xe1,0x0e,0x92,0x7a,0x70,0x27,0x19,0xfc,0x1d, +0x0e,0x3b,0xa2,0xef,0xc0,0x0c,0xa0,0x55,0x4d,0x3d,0x3c,0x8f,0x83,0x2b,0xe5,0x73,0x38,0xc4,0xf9,0x4e, +0x3c,0xbc,0xbb,0x0a,0xd7,0x54,0x3f,0x0c,0xaf,0x5c,0xc1,0x6a,0x67,0x65,0x1a,0x78,0x92,0xad,0x53,0x04, +0x5c,0xbe,0xc0,0x36,0xb1,0x5e,0xed,0xef,0xab,0x0b,0x23,0x27,0xa6,0x09,0x1c,0x01,0x5a,0xa8,0x77,0x08, +0x5b,0xb5,0xa6,0x44,0x1c,0x3a,0x96,0x96,0x94,0x7c,0xc1,0x51,0x62,0x2f,0xf0,0x02,0x7d,0x8d,0x5f,0x9d, +0xdd,0xdc,0xf3,0xe7,0x7a,0x96,0xeb,0x49,0x5b,0x7f,0x10,0x4a,0x7f,0x50,0x06,0xc9,0x64,0xa5,0xcd,0xa8, +0x1a,0xf5,0x25,0xea,0x6f,0x44,0x59,0x05,0x2b,0x1d,0x0c,0xd1,0x37,0x23,0x22,0xcb,0x14,0xcd,0xb4,0xb8, +0xe0,0xff,0x64,0xb9,0x56,0xc2,0xa2,0xfd,0xfd,0xfa,0xea,0x65,0x93,0x37,0xb3,0xa8,0xb4,0x5f,0xce,0x1f, +0x9d,0xba,0xc0,0xec,0xfa,0xef,0xcc,0x5e,0x1d,0xe5,0xf1,0x9e,0x09,0x9c,0x7f,0x62,0x02,0xcb,0x3c,0xe0, +0x62,0x8b,0xb0,0x60,0x54,0xc8,0x06,0xee,0x1e,0x42,0xcf,0x39,0x7d,0x3d,0x95,0x10,0x8e,0x6d,0x12,0x0c, +0x1f,0x22,0xf6,0x9d,0x07,0x8e,0xde,0xc5,0x15,0x70,0xf8,0x20,0x5f,0x0a,0x57,0xba,0x7d,0x19,0xab,0x0d, +0xc3,0x15,0x88,0xc3,0x1e,0xe6,0x6d,0x0f,0x7e,0xd3,0x7a,0x01,0x6c,0x36,0x4c,0xc2,0x63,0x70,0xf9,0xb9, +0x8c,0x7e,0x01,0xc8,0x33,0x99,0xc6,0xf3,0xa1,0x99,0xc5,0x54,0x4d,0x9a,0x5a,0x39,0xa7,0x2b,0x0c,0x8e, +0xb0,0xeb,0x3c,0x7c,0xe8,0x48,0x28,0xae,0x5e,0xf5,0x9c,0x67,0xb6,0x9e,0x28,0x19,0xec,0xed,0xec,0x6f, +0x1a,0x33,0x67,0x30,0xa0,0x79,0x29,0x93,0x02,0x53,0x5d,0xae,0xaa,0xc9,0xe9,0x8d,0x23,0xaa,0xcf,0xaa, +0x92,0x86,0x5d,0x50,0xd5,0xa2,0x7c,0x41,0x74,0x35,0x92,0xeb,0x6b,0xfd,0xc1,0x95,0x6f,0x76,0x4f,0xb5, +0x42,0x2e,0x35,0x2b,0x2c,0xe1,0x86,0x62,0x9a,0x51,0x26,0x89,0x66,0xef,0x79,0x39,0x56,0x80,0xa7,0x0b, +0xd0,0xc7,0x6b,0xcf,0x8c,0xa7,0x61,0xa5,0x17,0x7d,0x4c,0x0f,0x9e,0xae,0x34,0x97,0xc7,0x2d,0x81,0xea, +0x5a,0x66,0xa6,0x49,0xef,0x48,0x39,0x7b,0x32,0x31,0x1d,0x88,0x70,0xf5,0xb6,0xdb,0xed,0xa8,0xa6,0x61, +0x19,0xaa,0xb9,0x74,0x91,0x20,0x0c,0xb0,0xbf,0x66,0xd6,0x47,0x44,0x2e,0x4d,0x2e,0x1b,0xa0,0x66,0xae, +0x5a,0x10,0xe2,0x77,0xa5,0xcb,0x63,0xb3,0xe7,0x69,0x21,0xde,0xdf,0x3c,0xbb,0xe6,0xed,0x59,0x6a,0x5e, +0x2b,0xde,0x62,0x0d,0x3f,0x99,0x82,0xb6,0xfe,0xc3,0x71,0x79,0xdc,0x2c,0x8b,0x7d,0xd3,0xd6,0xf0,0x55, +0x35,0x6f,0x14,0xb4,0x77,0x51,0x4d,0x70,0x06,0x17,0x12,0x6e,0x95,0x66,0xc5,0x2a,0x8f,0x9f,0xa9,0x46, +0x23,0x2c,0xab,0x75,0x6b,0x79,0x2e,0x14,0x32,0x5c,0xb2,0x94,0xa2,0xaa,0x92,0x6a,0x1f,0x2a,0xec,0xa4, +0x08,0x28,0x0b,0x57,0x39,0x37,0x21,0xbe,0x85,0xea,0x03,0xfb,0x2e,0x9a,0xb1,0x49,0x01,0x2d,0x4f,0x74, +0xc9,0x88,0x45,0xef,0xcb,0x8c,0x08,0x29,0x28,0x76,0xf9,0x64,0xa7,0xef,0xd7,0x39,0x8c,0xc1,0x55,0xdd, +0x92,0x21,0xd5,0xf5,0xda,0x07,0xc8,0x09,0x9d,0xf4,0x89,0x29,0x86,0x83,0x84,0xe9,0xec,0x5e,0x5e,0x5f, +0xc7,0x8b,0x04,0xf8,0xb5,0x9d,0xf9,0x16,0xc3,0xdc,0xac,0x0e,0xfe,0xa2,0xba,0x55,0x0e,0xf3,0xb5,0xd5, +0xe3,0x16,0xaa,0x14,0x9a,0x2b,0x88,0x6d,0x3f,0xc4,0xd9,0x43,0x44,0x05,0x7e,0x88,0xdf,0x77,0xdd,0xd6, +0xc0,0x64,0x66,0xa1,0xce,0xc4,0x7e,0x5d,0xbe,0x87,0x75,0x82,0xaa,0xaf,0xa7,0x0e,0x6f,0xd5,0x9c,0xb5, +0x25,0xc9,0xc4,0xe2,0x2c,0x20,0x0a,0x20,0x62,0x2d,0xcc,0xb5,0x11,0xb2,0x2b,0xde,0x13,0xb0,0x4d,0x17, +0x3a,0x8e,0xf6,0xaf,0x82,0x65,0x5b,0x56,0x1b,0x5d,0x4b,0x35,0x48,0xe3,0x95,0x15,0xa5,0x1e,0x30,0x18, +0x00,0xdb,0xf7,0xb5,0x01,0xf4,0x75,0x71,0xac,0xa8,0x90,0xfe,0xdc,0x2d,0x0f,0xe7,0x59,0xce,0x76,0xd8, +0x65,0x7d,0x3f,0xa0,0xc9,0x0c,0x34,0x27,0x0c,0x13,0xa6,0xd5,0x1a,0xd1,0xbb,0x2d,0x79,0x37,0x90,0x3e, +0x89,0x40,0xb4,0x01,0x77,0xe2,0xa1,0x20,0xfa,0x3c,0x09,0x0f,0x95,0x1a,0x74,0x09,0x7a,0x07,0x0e,0x7e, +0xcb,0x70,0x59,0xf3,0x02,0x60,0x4e,0x50,0xb9,0x02,0xdb,0xd9,0xea,0x5c,0x7b,0x15,0x4c,0xd0,0xd2,0x44, +0xd5,0x60,0xb5,0xba,0x3a,0x55,0x94,0x01,0x39,0xed,0xea,0x02,0x90,0xb3,0xe6,0x60,0xb1,0xf0,0x96,0x4d, +0xe1,0x8a,0x9c,0x9b,0x7d,0x0e,0xf8,0x1b,0xbe,0x11,0x74,0x45,0x02,0x35,0x8d,0x1f,0x78,0xc9,0x5a,0xf4, +0x02,0xf8,0x55,0xf1,0x62,0x53,0x90,0x66,0xee,0x92,0x6d,0x8c,0xb5,0xff,0xa7,0xbc,0x53,0x48,0xe8,0x4b, +0x83,0x84,0x4e,0xfb,0x3c,0x67,0x99,0x19,0x40,0x9b,0xcc,0x6c,0x91,0x85,0x42,0x27,0xc1,0x9c,0x08,0x96, +0xd5,0x58,0x64,0xdb,0x2a,0xf2,0xaf,0xac,0xce,0xf5,0x71,0xf9,0xc9,0xaf,0x4a,0x25,0xf6,0x5f,0x33,0xa8, +0x0a,0xd3,0xda,0x98,0x2b,0x8d,0x91,0xed,0xd6,0xb6,0x52,0x23,0x78,0xd7,0xad,0x94,0xbe,0x7e,0xec,0xdf, +0x11,0xc1,0x7f,0x1d,0x6b,0x4d,0x6b,0x53,0xf3,0xca,0xba,0xce,0x96,0x49,0x97,0xc5,0xe7,0x69,0xf5,0x08, +0xd6,0x46,0x92,0x46,0x4b,0x2e,0xc0,0x48,0xb9,0xbb,0xde,0x6d,0x83,0x3f,0xfc,0x79,0xeb,0xcd,0x34,0x9e, +0x35,0xb4,0xc0,0x3b,0x1b,0xab,0x24,0x94,0x9f,0x68,0xde,0x4d,0x9e,0x94,0xfa,0x5a,0x29,0x9f,0x59,0x24, +0x01,0x8b,0xe7,0x6e,0x67,0xb0,0xa9,0x10,0x9b,0xac,0xd7,0x9b,0xc4,0x1c,0x5a,0x54,0xf7,0x2b,0xeb,0xcd, +0xd4,0x76,0x11,0xdc,0xc1,0x12,0x02,0xf0,0x84,0x5f,0xad,0xcf,0x95,0x16,0x5b,0xc1,0xae,0xdd,0x29,0x3e, +0xa0,0xa3,0x1f,0x68,0x6e,0x9f,0x00,0xc5,0x4a,0x9c,0xc1,0x90,0xba,0xd6,0x17,0x17,0x82,0xba,0xe6,0x23, +0xec,0x46,0x8d,0x7e,0x71,0xf8,0x4d,0x92,0x3a,0x5b,0xff,0x7c,0xb9,0xce,0xef,0x2b,0x22,0xb4,0x8b,0x40, +0xe2,0x5a,0x09,0x78,0xb0,0xbb,0x80,0x8c,0x78,0x6e,0xc8,0x57,0x69,0x6d,0xee,0x2a,0xc2,0xd1,0xf2,0x1b, +0x96,0xe4,0x23,0x4b,0xd9,0x15,0x44,0x1f,0x8e,0x2f,0x01,0x4b,0x21,0xe7,0xa2,0x62,0xe2,0x6b,0x15,0xe0, +0x24,0xaa,0x06,0x46,0x94,0xd1,0xed,0xe3,0xa3,0xb6,0x25,0xdf,0x89,0xf8,0x28,0x3f,0x8f,0x69,0x47,0x88, +0x25,0x78,0x61,0x70,0x67,0xef,0x8b,0xf5,0xc3,0x5d,0x6f,0xc9,0xb1,0xda,0x1f,0xb1,0x63,0xd5,0x26,0x99, +0x04,0x94,0xb4,0x9f,0x0c,0xa5,0x50,0xe6,0xb2,0xcd,0x77,0x54,0xe6,0x56,0x99,0x3f,0x19,0x7a,0xa6,0x65, +0x23,0x52,0x7b,0x6b,0xf3,0x04,0x1d,0x8f,0xdd,0x52,0x1b,0x54,0xb5,0xf3,0xaa,0x89,0xaf,0xeb,0x3e,0xc6, +0x92,0x7a,0xe2,0xf2,0xd6,0x5b,0x1a,0xf7,0xda,0x7a,0x0b,0xb4,0xa7,0x2d,0x5b,0x7a,0x48,0x32,0x79,0x90, +0x14,0xea,0xe8,0x79,0x2b,0x07,0x51,0xbc,0x08,0x0d,0xda,0x86,0x79,0xb4,0xd9,0x54,0x1a,0xd1,0xd6,0x4b, +0x69,0x4d,0xd5,0x3f,0x38,0xda,0x26,0x37,0xc1,0xa9,0x2a,0x50,0x4e,0x78,0x3d,0x58,0xfb,0xfb,0x8f,0xe4, +0xa8,0xe0,0x3b,0x3b,0x56,0x8e,0x7a,0x52,0x1d,0x0f,0x81,0x19,0x60,0x99,0x18,0x35,0x8a,0x21,0xae,0xdf, +0x4b,0x12,0x86,0xd8,0x89,0x17,0x26,0x49,0xed,0x5e,0x09,0x2a,0xa5,0x03,0x60,0x1c,0x59,0x71,0xa2,0xe2, +0x9d,0xa5,0xbc,0xa1,0xca,0xe4,0x3a,0x7e,0x5f,0x46,0xd7,0xab,0x50,0x3a,0x54,0xdf,0x32,0xe9,0x9a,0x42, +0x86,0xc9,0xe7,0x88,0x28,0x50,0xac,0xbd,0x80,0x0f,0xa5,0xc6,0x76,0xc0,0x1a,0xef,0xf6,0xae,0x1b,0xde, +0x59,0xbe,0xe4,0x81,0x7e,0xef,0xb7,0x87,0x82,0x3a,0xb1,0x8b,0x8c,0xe2,0xc7,0xf7,0x90,0x43,0xfc,0xfe, +0x7d,0x72,0xbd,0xe6,0xe6,0xc3,0xb8,0xad,0x4e,0x65,0xb4,0xcd,0xfd,0xdb,0x13,0x66,0xbc,0x6b,0x76,0xdc, +0xf8,0x38,0xf7,0xd5,0x5b,0x53,0x08,0x03,0x26,0x36,0x48,0x19,0xda,0x0b,0xeb,0x94,0xcc,0x7f,0xa5,0xdc, +0x76,0xab,0xee,0x29,0xb9,0x45,0x31,0x49,0xd1,0x5d,0x5d,0xf4,0x5f,0xa9,0xc3,0x3d,0x5d,0xfc,0x89,0xca, +0x74,0x7d,0xe9,0xaa,0x09,0xd6,0xae,0xec,0xb6,0x72,0x95,0x8d,0x96,0xe5,0xdf,0xe3,0x8f,0x38,0x8d,0xce, +0xf9,0xd8,0x60,0x2f,0xf3,0x39,0xd6,0xfa,0xd2,0x1c,0x61,0x57,0xb0,0x19,0x5d,0x9c,0x66,0x6b,0x46,0x37, +0xc3,0x93,0x32,0x5f,0xaa,0xaf,0x16,0x71,0x19,0x25,0x4b,0x5c,0xf1,0x58,0xbc,0x25,0x26,0x9d,0x3f,0xba, +0xa6,0xe7,0x2a,0x09,0x15,0x1c,0xff,0xa8,0x2f,0xfe,0x89,0x0b,0xd6,0xb4,0xaa,0xb7,0x1f,0x92,0xf8,0x06, +0xbf,0x0e,0x02,0x20,0x3b,0xaa,0x3c,0x8e,0x84,0x8c,0xeb,0x5f,0x25,0x11,0xfd,0xe8,0x27,0x0a,0x16,0xd2, +0x5c,0x49,0x85,0x96,0x09,0x15,0xfe,0x63,0x75,0xc9,0xc5,0x64,0x17,0x17,0x74,0x74,0xff,0x58,0x5d,0xf2, +0x53,0x25,0x7f,0x7c,0xb9,0xb0,0x6e,0xf8,0xc8,0x41,0xc5,0xe6,0x79,0x1c,0xa7,0x3f,0x56,0x97,0xfc,0x85, +0xec,0x0a,0x56,0xfb,0xcb,0x4c,0x07,0xd8,0xe2,0x1b,0xf3,0xfc,0xe6,0x2a,0xe9,0xe2,0xec,0x42,0x4d,0xa1, +0xd6,0xb1,0xe5,0xe3,0x21,0xa7,0xdf,0xdf,0xff,0xbb,0x81,0xbf,0x64,0x78,0xad,0x89,0xb2,0x34,0x37,0x21, +0xa1,0x27,0xd5,0x25,0xed,0x51,0xa6,0x2f,0xcc,0xf7,0xb6,0x95,0xcf,0xbf,0x1a,0x79,0x1d,0xee,0x97,0x80, +0x6a,0xa2,0xbf,0x8f,0x82,0xcf,0xe9,0xef,0x51,0x30,0x0a,0xd4,0x87,0x6a,0x1a,0xf0,0x56,0xa1,0xa8,0x3a, +0xcb,0x87,0x9a,0x85,0xb5,0x58,0x81,0x79,0xe0,0xf0,0x35,0x9d,0x1e,0xb9,0xe3,0xf3,0xe5,0x32,0x8e,0x3e, +0xc4,0xfa,0x31,0x9d,0xa8,0xba,0x1b,0x55,0x72,0x75,0x27,0x1f,0xa8,0x1b,0xf5,0x89,0x7e,0xc5,0xe7,0x7a, +0xcb,0xad,0xb5,0xce,0xff,0xc4,0xb3,0xf0,0xae,0x46,0x13,0x94,0xbe,0x16,0x9a,0xd0,0xa5,0x10,0xa8,0xad, +0xce,0xd6,0x68,0x2f,0x1c,0x76,0xa5,0xb6,0x1f,0xfb,0x59,0x18,0x57,0x2c,0x98,0xd1,0x76,0xb1,0x6d,0x00, +0x4b,0x30,0x6c,0xc5,0x1d,0xbb,0xbb,0x12,0xd3,0x26,0xdd,0x18,0x56,0xac,0x98,0x2d,0x14,0xee,0xf6,0x17, +0xf2,0xd5,0x37,0x8c,0x47,0xd6,0x56,0xb5,0xd7,0x20,0x4d,0xb5,0x82,0x4f,0x55,0xe6,0x6b,0xa3,0xe6,0xe6, +0xc7,0x5b,0x3f,0x4b,0xdb,0x92,0xb2,0x1d,0xa9,0x11,0xa2,0x06,0xd3,0x7c,0x97,0xbd,0x22,0x5b,0x83,0xb4, +0x77,0x4d,0x3c,0x31,0x9d,0x62,0x02,0x32,0xd9,0x3d,0xc5,0xce,0xfb,0x0d,0xe6,0xde,0x1b,0x52,0x49,0x6e, +0x5e,0x31,0xb8,0x93,0xdc,0xf4,0x50,0xdf,0x19,0x3a,0x7d,0xeb,0x55,0x50,0xbd,0xf2,0x2b,0xfe,0x88,0x2e, +0x35,0x13,0xcb,0xbb,0x54,0xdd,0x02,0xb7,0xc2,0x60,0x61,0xaf,0xdc,0x3d,0x0e,0x4e,0x2e,0xfb,0x26,0x95, +0x4b,0x3c,0x91,0x8f,0xe0,0x3d,0x9d,0xc0,0x21,0x65,0x4f,0x58,0xdd,0xca,0x81,0xa8,0x0a,0x78,0xca,0x9e, +0x8c,0xb0,0xac,0xd5,0xfa,0xee,0x54,0xf3,0xc5,0x69,0x78,0xaa,0x76,0xcb,0x0e,0x95,0x7f,0x4d,0x0a,0xa4, +0xfa,0x3c,0x15,0xc3,0x1f,0xa5,0x4b,0x2c,0x4b,0x28,0x0c,0x27,0x3d,0xa8,0x54,0x36,0xe7,0xd0,0x6d,0x2c, +0x37,0xf1,0xf5,0x39,0x11,0x32,0x57,0xf9,0x26,0xb9,0xbe,0xdc,0x30,0xe5,0xb9,0x59,0x26,0xe9,0xaf,0x1b, +0xec,0x8c,0x1b,0xa2,0x3a,0xa2,0x6b,0xcf,0xdd,0xad,0x63,0x7c,0x28,0x38,0x37,0xde,0xd9,0xc1,0x93,0x83, +0xcb,0xc4,0x4f,0x51,0x80,0x28,0x17,0x37,0xc7,0xac,0xb6,0xdd,0x1c,0x23,0xb7,0x83,0xc4,0xcf,0xe9,0x95, +0x52,0xf8,0x00,0x28,0x67,0x12,0x4c,0x7f,0x0a,0x67,0x9b,0x90,0xae,0xb5,0x1e,0x68,0x08,0x7d,0x65,0x02, +0x85,0x0a,0x91,0x00,0xf1,0xd9,0x81,0x3b,0x7c,0xe8,0x1d,0xf8,0x19,0x1e,0x50,0xaa,0xe3,0x1e,0xf4,0x2b, +0xd3,0x93,0x67,0x4f,0x4f,0x9f,0x9e,0x4d,0x37,0x83,0x81,0xb7,0xc1,0x83,0xd9,0xd9,0x0c,0xd7,0x4f,0x28, +0xc5,0x83,0x86,0x85,0x5f,0x79,0xbd,0xa4,0xe3,0x79,0x37,0xe0,0x50,0x85,0x9e,0x5d,0x12,0xb1,0x7c,0xfc, +0xe0,0xf0,0xc9,0xf1,0xc1,0x83,0xa3,0x27,0x8e,0x80,0x83,0xb4,0xa6,0x74,0x03,0x92,0x14,0x1b,0x9f,0xad, +0x7c,0xf2,0xd7,0xe1,0xfd,0x2a,0x75,0x71,0x51,0x6b,0xa9,0xb1,0x24,0xaa,0xa1,0x0d,0xc2,0x75,0x58,0x7f, +0xa0,0x4c,0x34,0x05,0xa8,0x0c,0x18,0x12,0x9e,0x08,0x9f,0xae,0x5d,0x76,0x37,0xb9,0x76,0x25,0xc0,0x31, +0xab,0x7e,0x34,0x66,0x8a,0x02,0x1e,0xf9,0xc5,0xcd,0x10,0x15,0x2a,0x62,0xf4,0x1a,0x8e,0x62,0x08,0x73, +0x32,0x4f,0x24,0x04,0xd9,0x66,0xc3,0xdf,0x46,0x61,0x84,0xab,0x62,0x67,0x2e,0xcf,0xec,0x5c,0x58,0xfa, +0xf8,0x8c,0x7a,0xa4,0x30,0xd3,0x9a,0xab,0xe2,0x3b,0x32,0xec,0x10,0xed,0x1a,0xbf,0xe3,0xfd,0xfd,0x5b, +0x37,0xf2,0x11,0x9d,0xe2,0x1a,0x62,0x46,0x9d,0x82,0x19,0x74,0x58,0xa3,0xa4,0x2d,0x2b,0x33,0xed,0x23, +0xad,0xc4,0x8c,0x2d,0x31,0x20,0x35,0x78,0x34,0x36,0x07,0x09,0x22,0xea,0xc1,0x70,0x64,0x9c,0x09,0xec, +0xcb,0x1b,0x65,0x0b,0x0f,0xc4,0xa1,0x74,0xfa,0xb6,0x22,0x42,0xe5,0x99,0x96,0xbc,0x57,0x46,0xcd,0xfa, +0x09,0x4c,0x04,0x27,0xcd,0x25,0x84,0x4d,0x2c,0x68,0xc8,0x65,0x51,0x2b,0x2d,0xee,0xf3,0xc6,0xb5,0x32, +0xd4,0x6a,0xdd,0xa6,0xd3,0x77,0xb1,0x65,0xd1,0xec,0xd6,0xee,0xf5,0x92,0xee,0xd8,0x71,0x17,0x8c,0xe1, +0xd8,0x35,0x51,0x7f,0xd3,0xab,0xb9,0x5b,0x33,0xd1,0x4a,0xe7,0x75,0xe0,0x45,0xab,0x24,0x2d,0xfb,0xc4, +0xb8,0x6d,0x3a,0xcd,0xda,0x37,0x64,0x20,0x16,0x09,0xca,0x90,0x81,0xd1,0xb4,0xbd,0xd6,0xbe,0x73,0xa8, +0x64,0x58,0xcd,0xf9,0xdb,0x78,0xf6,0x65,0xf3,0x11,0x8c,0xe4,0x99,0xad,0xa8,0xf0,0xf3,0xc3,0xb8,0xb2, +0x51,0x8c,0x5b,0x46,0x5a,0x80,0x64,0x61,0xa5,0x73,0x87,0xe9,0xc6,0xd3,0xc6,0xe1,0x56,0x6b,0x9e,0x92, +0xa3,0x35,0x4a,0x3f,0xec,0x78,0xf6,0x65,0xf3,0x91,0x26,0x8c,0x7e,0xd5,0x1d,0x3b,0x2e,0x1b,0x31,0x6d, +0x59,0x24,0x42,0x47,0xd5,0xff,0x0f,0x2a,0x46,0xbb,0x4e,0x9c,0x97,0x5f,0x31,0xb7,0x8f,0x1d,0xab,0x86, +0x0b,0x82,0x6a,0x8a,0x20,0xe0,0xbf,0x5a,0x4b,0x2e,0xd7,0x46,0x80,0x6f,0x3c,0x68,0x95,0xcb,0x46,0x34, +0x18,0xad,0x8b,0xb2,0x2e,0x05,0xf9,0x9f,0x2a,0xad,0x86,0x68,0x88,0x92,0x5b,0x60,0x07,0x06,0x25,0x8a, +0x05,0xf2,0x42,0xb7,0xba,0xc2,0xe1,0x00,0x86,0x91,0xb5,0x05,0x4d,0x28,0x44,0x36,0xc4,0xd7,0x7b,0x94, +0x8b,0xfd,0x0b,0x20,0x74,0x7e,0x2d,0xa2,0x1d,0x90,0x0b,0x6a,0x87,0x7b,0xc7,0xc1,0x61,0xd9,0x69,0x29, +0x82,0x19,0xe8,0xc1,0xa5,0x72,0xe9,0x29,0x27,0x20,0x12,0xb9,0x15,0x30,0xfe,0x6f,0xf7,0xd6,0xa5,0x3a, +0x66,0xea,0x76,0xbc,0x38,0xdb,0xfe,0xe8,0xf2,0x96,0x99,0xa2,0xec,0x1a,0x59,0xd3,0x97,0xd2,0x3e,0x5f, +0x03,0x1b,0xac,0xdb,0x76,0xb7,0xa2,0x32,0xe8,0x16,0x56,0x66,0x1a,0x9d,0x7e,0x24,0xec,0x58,0x65,0x30, +0x7f,0xe9,0xe6,0x9f,0xf1,0xd4,0xfd,0xde,0x80,0xcb,0xb1,0x5a,0x13,0x76,0x37,0x5e,0x2b,0x10,0xdc,0x0c, +0x40,0x29,0xd4,0xd2,0xda,0x91,0x0d,0xad,0x29,0x3b,0x23,0xb3,0x1b,0xc3,0x71,0xce,0x22,0x6c,0xd5,0x90, +0x54,0x1a,0x52,0xaf,0x67,0x7b,0xcc,0x4a,0x19,0x33,0xdb,0xbe,0x04,0x99,0x86,0x23,0x2b,0x92,0xe7,0xb6, +0x54,0x93,0x4c,0xef,0x70,0xb2,0xc0,0x59,0x66,0xb9,0x7b,0x2b,0x52,0x94,0x43,0x1d,0x8e,0x42,0x73,0xce, +0x53,0x63,0xa4,0xb6,0x7b,0xae,0x57,0x66,0xb6,0xf5,0x09,0x3e,0xb6,0x81,0x41,0x64,0x6d,0x1f,0x8f,0x3a, +0x5a,0x86,0x55,0xa6,0x6c,0x1b,0x55,0x5d,0x54,0x84,0x70,0x85,0xe4,0x08,0x4c,0x99,0x1a,0xd8,0x94,0x34, +0xeb,0x34,0x0b,0x1c,0xb9,0x72,0xf4,0xb6,0x85,0x47,0xea,0xd2,0xf1,0xed,0xe5,0x15,0x38,0xb2,0x63,0xe8, +0xa7,0x4f,0x79,0x41,0x3b,0xbc,0xae,0x1d,0xdd,0x03,0x80,0x60,0x72,0xac,0xde,0xe8,0xe2,0x97,0x1a,0x30, +0x40,0xd6,0x31,0x6f,0xf0,0xc0,0xc5,0x4b,0x2c,0x33,0xf1,0x70,0x00,0x08,0x43,0x4b,0x35,0x3a,0x0e,0xb3, +0x71,0x44,0xe3,0x9e,0x86,0x11,0xbb,0x00,0x57,0x86,0xb8,0xb2,0x2a,0x40,0x78,0x41,0x35,0x81,0xf8,0x38, +0xb4,0x94,0x61,0x8b,0x14,0xc5,0x8a,0xe1,0xc9,0x61,0xde,0x02,0x5c,0xaf,0xda,0x1a,0xb5,0x60,0x7d,0x72, +0x43,0x18,0x47,0x20,0x32,0xaf,0x69,0x98,0x92,0xf4,0xc0,0x2f,0xca,0x86,0x01,0xa7,0x36,0xda,0x9c,0xf4, +0x56,0xb7,0x9e,0x58,0x6e,0xf6,0xb5,0xe1,0xe6,0xba,0x0c,0x3b,0xc6,0xb4,0x4e,0xfc,0x19,0x6b,0xa4,0x24, +0xbe,0xa9,0x85,0x27,0xc9,0x56,0x90,0x6f,0x32,0xb9,0x1f,0x7b,0x52,0xdb,0x93,0xec,0x9a,0x48,0xf0,0x78, +0xf1,0x1e,0xc4,0x33,0xac,0x50,0x6b,0xd6,0x63,0x06,0x37,0xa1,0x14,0xa9,0x72,0xe1,0xdd,0x15,0xca,0xb0, +0x73,0x5e,0x14,0x1c,0xe2,0xd3,0x39,0xcf,0x6e,0x07,0x45,0xf2,0x3b,0x2d,0xcd,0xe0,0x3c,0xcb,0x17,0x71, +0x3e,0xa0,0x27,0xe3,0x95,0x02,0x7c,0x0e,0x34,0xde,0xf6,0x58,0x59,0x73,0x06,0xe7,0xf0,0xcf,0x1e,0x4b, +0xe3,0x83,0x68,0x5d,0x66,0x63,0xf9,0x2c,0x38,0x5c,0xd1,0x67,0xc4,0x71,0x23,0x27,0x5c,0x97,0xd9,0x2a, +0x38,0xfc,0xf3,0x98,0xf1,0x99,0x83,0xc7,0xa3,0x3f,0x3b,0x7e,0x61,0x1b,0x6e,0x39,0xfe,0xdf,0xea,0x86, +0x6b,0x91,0x62,0x3a,0x04,0x17,0xb8,0xde,0x30,0xa2,0x1e,0xd3,0xd0,0x39,0xfc,0xb3,0x23,0x26,0x3f,0xd9, +0x8a,0xc6,0xde,0x39,0x5a,0x89,0x74,0x7c,0x28,0x95,0x81,0xdd,0x2b,0xc0,0x41,0x3e,0xd7,0x8f,0xb9,0x64, +0x5f,0x37,0x58,0x12,0xb1,0xb5,0x6c,0xe8,0x70,0x75,0x12,0x2b,0xad,0xf5,0x16,0xf5,0x12,0xa2,0x49,0xd7, +0x8b,0xa8,0x77,0x06,0xaa,0xd8,0xd6,0x34,0x7d,0x1d,0xe6,0x74,0x6c,0x69,0x87,0xd4,0xdd,0x6f,0xc6,0xaa, +0x2e,0xac,0xb1,0x94,0x5a,0xc1,0xec,0x1d,0x86,0x82,0xd4,0x09,0xcb,0x64,0x15,0x3a,0x0a,0x3c,0x0b,0x63, +0x80,0xfe,0xaa,0xdb,0xab,0x75,0x7f,0xc2,0xb6,0x6e,0x6c,0xac,0xcd,0x7c,0x02,0x77,0x58,0x3d,0x23,0x6a, +0x61,0x77,0x79,0x44,0x7b,0xb7,0x66,0x03,0x8f,0xe5,0x48,0x0d,0xdb,0x5f,0x69,0x1c,0x05,0x67,0x9b,0x1e, +0x61,0x40,0x47,0xe3,0x25,0x75,0x73,0x30,0xf8,0x92,0xfe,0xb3,0xc6,0x7b,0xa4,0x26,0xc4,0x80,0x07,0x7d, +0x65,0xcd,0x9f,0xe8,0x9c,0x81,0x31,0x68,0x57,0x88,0x6a,0xa3,0x5d,0xd8,0xfe,0x1e,0x8b,0xd8,0xbf,0x5b, +0x25,0xb7,0xf1,0x52,0xe3,0x8c,0x77,0xd0,0x01,0x50,0xea,0xa6,0x44,0x95,0x64,0xb7,0xef,0x79,0xb6,0xbe, +0x8b,0x97,0xc9,0x0e,0xec,0x21,0xf6,0x86,0x00,0x24,0x0b,0xe5,0xf8,0xba,0x1a,0xd8,0x1d,0x29,0x13,0x0e, +0xd1,0xca,0x79,0xbd,0x36,0x13,0x69,0x47,0xda,0x6c,0x0b,0x84,0x5e,0x65,0x20,0xb8,0x64,0x63,0x3e,0xd8, +0x3d,0x6f,0x58,0xf9,0x45,0x0b,0x7e,0x30,0x9f,0xc6,0xb4,0xb5,0x0c,0xfb,0xc4,0x89,0xce,0xf1,0x7a,0x30, +0x38,0xf0,0x2f,0xca,0xf0,0xce,0xf4,0x87,0x53,0x75,0xc8,0x87,0xa4,0x48,0xce,0x93,0x65,0x42,0xc4,0x87, +0x73,0x95,0x2c,0x16,0x71,0xea,0xf8,0x7a,0x95,0x39,0xbc,0xcc,0x68,0x77,0x5c,0xd1,0xc7,0xcb,0xb8,0xa4, +0x3d,0xf4,0xfd,0x2a,0x9a,0xa3,0xaf,0x9d,0x91,0xe3,0x5f,0xd0,0xe8,0xfe,0x20,0xe3,0xe2,0x7c,0x3e,0x1a, +0x51,0xba,0x45,0x19,0x4e,0x9d,0x1f,0xe2,0xf3,0x5f,0x13,0x18,0x83,0xbf,0xce,0x7e,0xa7,0xbf,0xd7,0x85, +0x33,0xa3,0xb3,0x7f,0xd7,0x74,0x94,0xb1,0xb7,0x79,0x60,0x9a,0x06,0xe2,0xe0,0x71,0x97,0xa1,0x30,0xaa, +0xd8,0x5d,0xdb,0x49,0x93,0x19,0x43,0xb5,0x73,0xbd,0x02,0x9f,0xa6,0xd2,0x1a,0xda,0xc6,0x91,0x60,0x8e, +0xce,0xa1,0x13,0xa4,0xac,0xdc,0xa1,0x6c,0xbf,0x5d,0x5f,0x9f,0x23,0x76,0x68,0x94,0x26,0xd7,0x2c,0xaf, +0x7d,0x49,0x2d,0xe2,0x0b,0x56,0x8f,0x8b,0x4e,0x71,0xb9,0xbe,0xae,0x6e,0xe9,0x54,0x5f,0xbe,0x51,0xb5, +0xc0,0xed,0x32,0xbe,0xfd,0x26,0xcf,0x6e,0xf4,0xf5,0xfb,0x2b,0xa2,0x26,0x7e,0xe5,0xbb,0xaa,0x2f,0xe8, +0x8e,0xa8,0xba,0xf8,0x85,0xb9,0xcb,0xaa,0x0c,0x64,0x62,0xf3,0xc5,0x8a,0x18,0x32,0x91,0x6c,0x26,0x8b, +0xec,0x86,0xaf,0x7e,0xe7,0x98,0x44,0x7c,0x95,0x65,0xd7,0xac,0x65,0xa4,0x5a,0x43,0x78,0x48,0x9d,0xe1, +0x5c,0x2c,0xb3,0xa8,0x74,0x02,0x87,0x1e,0x3d,0xe7,0x4b,0x08,0xc6,0x3f,0x2e,0xbb,0xa4,0x58,0x22,0x8f, +0x7a,0xd4,0xe0,0xd1,0xff,0xda,0xb8,0x57,0x46,0xea,0xb5,0xf0,0x11,0x2d,0xcf,0xcd,0x75,0x38,0x57,0xe4, +0x51,0xe9,0xb1,0xfd,0x80,0x8c,0x97,0x9a,0x8e,0x6b,0xf6,0x1b,0x7e,0x03,0x97,0x04,0x3f,0x52,0x56,0xf7, +0x3c,0x78,0x74,0xae,0x89,0xd4,0x4f,0xdf,0x17,0x33,0xdf,0x72,0x62,0x8d,0xf6,0xf7,0x1d,0x1a,0x54,0x87, +0xf8,0xd9,0xc8,0x12,0xb2,0xc2,0xec,0x44,0xb9,0xea,0xc0,0x8b,0xdf,0x03,0x4c,0xc9,0x12,0x2e,0xa3,0xc4, +0xfa,0x2b,0x82,0x2d,0xb5,0xe0,0x84,0xe1,0xee,0x47,0x9f,0x3c,0x50,0xe4,0x1a,0x87,0x57,0x4f,0x18,0x08, +0x18,0x60,0x65,0xdc,0x1d,0x40,0x9e,0x09,0x9d,0x94,0x07,0xde,0x51,0xda,0x1e,0x21,0x69,0x71,0x98,0xa9, +0xe0,0x9d,0xfa,0xbd,0xca,0x31,0xed,0x33,0x64,0x11,0xc7,0xe4,0x75,0xa5,0x0d,0x32,0x73,0xa8,0x11,0x13, +0x07,0xa1,0x2f,0x6f,0x21,0x0f,0x68,0x6f,0x78,0x30,0x63,0x83,0x57,0xcc,0x66,0xc3,0x12,0xe3,0xca,0xf1, +0xaf,0xda,0xf0,0x60,0x38,0xe4,0xa2,0x49,0x21,0xb5,0xfd,0x2a,0xce,0x13,0x16,0x3e,0xc0,0xe9,0xb7,0xd1, +0x1b,0x21,0x4b,0x0a,0x22,0xe5,0xda,0x8b,0x51,0x65,0x8b,0xd6,0x09,0x02,0x77,0x94,0x95,0x62,0x1c,0x7e, +0xe4,0x9c,0x5d,0xca,0x08,0xa0,0x3c,0x61,0x3a,0x26,0xc4,0x1f,0x1d,0xe1,0xff,0x68,0x5c,0xeb,0x83,0x69, +0x8f,0xe1,0x08,0xbe,0xf0,0xd5,0xb8,0x8b,0x40,0xf8,0x15,0x57,0x0b,0xa1,0x4e,0x9c,0x34,0xcb,0xaf,0xa3, +0xa5,0xf2,0x23,0x63,0x0f,0xe1,0x55,0xc9,0x69,0x56,0x25,0x78,0x1c,0x89,0x50,0x40,0xdd,0x99,0x4e,0x68, +0x02,0x30,0xcc,0x32,0xcf,0x7c,0xb6,0x01,0x65,0x0c,0x87,0xcd,0x26,0x29,0x9e,0x03,0x99,0x1a,0x28,0x29, +0x93,0x8c,0x3a,0x3e,0x10,0xdc,0x98,0x8a,0x88,0x9c,0x3a,0x72,0x76,0xd0,0x56,0x24,0x51,0x1a,0x66,0x6d, +0x62,0xcf,0x6a,0x5d,0xd8,0xdc,0x6c,0xf4,0x82,0xd2,0xfe,0x8b,0xbd,0xa5,0xea,0xad,0x0e,0x1f,0x13,0x0f, +0x56,0xa3,0xa0,0x1b,0x58,0x51,0xf2,0x2e,0x9e,0x97,0x85,0x81,0x7d,0x55,0x71,0x75,0xbf,0xc2,0x2c,0xa0, +0xe9,0x5b,0x25,0xa1,0x14,0x5c,0xb1,0xc9,0x6b,0xd5,0x31,0xc1,0xef,0xe0,0x12,0x2f,0x2c,0xec,0x40,0xb3, +0xfd,0xeb,0x24,0xe0,0xa7,0x8a,0x8e,0x7a,0xea,0x68,0x93,0xf9,0xfe,0xfe,0xba,0x14,0x41,0x19,0x5d,0xbe, +0x93,0xaf,0x7c,0xa7,0xa2,0xad,0xea,0x4e,0x32,0xe6,0x3c,0x73,0xb0,0xee,0x00,0x30,0x53,0x09,0xca,0xda, +0x4b,0x0c,0xf3,0x9f,0x17,0xab,0x44,0xad,0xc6,0x6a,0x60,0x35,0xbb,0xb8,0xbc,0x60,0x2e,0xfa,0x69,0x95, +0x39,0x82,0x38,0xbf,0xe5,0xfa,0x45,0x46,0x82,0xa4,0xfb,0xdb,0x22,0x9a,0xc2,0x17,0x10,0x33,0xb6,0xcf, +0x40,0xbf,0x63,0xdf,0x97,0xaa,0xb9,0xd6,0x84,0xe0,0x23,0xa0,0xca,0xac,0x1a,0x89,0xce,0xee,0x06,0xf5, +0x30,0xe0,0x4e,0xbe,0xab,0xbe,0x09,0x46,0xdb,0x8e,0x0e,0xbf,0x3f,0x13,0x3a,0x87,0xfb,0x68,0xbf,0xcd, +0xb3,0x28,0xa2,0x94,0x28,0x22,0x4d,0x97,0xd0,0xa5,0xa2,0x68,0x9c,0x1f,0x78,0x06,0x76,0xb0,0x1b,0x66, +0x06,0xc6,0x7d,0xcc,0x41,0x11,0xbd,0x55,0xc3,0x5b,0x8b,0xcc,0x00,0x81,0xe7,0x1d,0x90,0x91,0x5a,0xdc, +0x6c,0x0a,0xe0,0x40,0xb1,0xa2,0xdd,0x73,0xbc,0x80,0x58,0xce,0x71,0x7e,0xfc,0x39,0x0b,0x44,0x13,0xca, +0xf9,0x2b,0x84,0xe7,0x44,0xfe,0x90,0x8d,0x6e,0x36,0xf4,0x77,0x70,0xc4,0xbf,0x23,0xcb,0x43,0x69,0xeb, +0x47,0x86,0x1f,0x36,0xfb,0x5f,0x55,0x37,0x6c,0x3f,0xe1,0x5b,0xaf,0x25,0x09,0x6c,0xee,0x3b,0xf7,0xb0, +0xf7,0x0d,0xc1,0x34,0xda,0x02,0xbe,0x89,0x86,0xb6,0x09,0x30,0x20,0xad,0xce,0x43,0x99,0xcb,0x49,0x65, +0x5c,0x1c,0x1d,0x27,0xcc,0x62,0x01,0x40,0x29,0x9a,0xcd,0xac,0xd9,0x06,0x6f,0x3a,0x3e,0x3b,0x0c,0x78, +0xcf,0xb6,0x26,0x2b,0x64,0x64,0x84,0x4b,0x35,0x59,0x55,0x5d,0x02,0x6b,0xb2,0x6e,0x59,0xe9,0xd3,0x76, +0x36,0xd6,0x8c,0xe9,0xe9,0x4d,0x1c,0xa7,0xe1,0x4b,0xff,0xe5,0x2e,0x13,0x80,0x97,0x3e,0xf6,0xa3,0x0e, +0x23,0x6c,0x04,0x0c,0x15,0xa6,0x9d,0x08,0x20,0x6d,0xc3,0x41,0x99,0xac,0x68,0xbd,0x28,0xf5,0x48,0x41, +0xa3,0x09,0x98,0x54,0x9e,0x4c,0xb8,0x19,0x6a,0xb3,0x19,0x49,0x21,0xce,0x3e,0x45,0x58,0x6a,0xed,0x73, +0x94,0x97,0x5a,0xc8,0x76,0x13,0x6a,0xd3,0x0a,0xad,0x9c,0xa6,0x71,0x09,0x73,0xb9,0x5c,0x03,0xbc,0x3f, +0x6b,0x1e,0x67,0x69,0x75,0x9c,0xd1,0xc1,0xb1,0xce,0xdb,0x52,0x01,0x6e,0xe5,0x4a,0xed,0x8d,0xba,0xbe, +0x66,0xb2,0xe8,0x58,0xe1,0x93,0xca,0x40,0xd6,0x0b,0xac,0x4f,0x4c,0xed,0xab,0xd7,0x44,0xe6,0xae,0x3b, +0x70,0xab,0x68,0xc3,0xb8,0xbf,0x28,0xbb,0xf9,0xc3,0xc5,0x5a,0xa8,0x36,0x85,0x61,0x9d,0x51,0x87,0x84, +0xa6,0xcb,0xa6,0x56,0x5f,0xce,0xb4,0xb4,0xad,0xf9,0xe5,0x43,0xc4,0x9f,0x3d,0xec,0x7e,0xa7,0x84,0xc7, +0x92,0xad,0x96,0xd6,0x51,0xf7,0xba,0xba,0x53,0x07,0x55,0xe7,0x7b,0x0f,0xcb,0x7e,0x75,0x57,0xcf,0xaf, +0x28,0xe3,0x95,0x12,0xd3,0xd8,0x8f,0x2a,0xc3,0x4e,0xb1,0x2c,0xd5,0xf9,0x6b,0x14,0x79,0x0e,0x01,0x4a, +0x7d,0x9a,0x1a,0x4f,0xf8,0x1d,0x7d,0x6a,0x5e,0x0b,0x14,0xd2,0xd6,0x9e,0x92,0x1c,0xad,0xc1,0x9a,0xa1, +0xd6,0x2b,0xdf,0xca,0x2c,0xbc,0x33,0x66,0x59,0x8d,0x63,0xaf,0x1e,0xac,0x71,0x4f,0xb4,0x3b,0xa8,0xaf, +0x25,0xe1,0xd5,0xba,0x74,0x3c,0x9e,0xc6,0x32,0x5e,0x54,0x7b,0xa5,0x80,0xe7,0xc4,0x72,0x24,0xa8,0x77, +0x93,0x7a,0x52,0x8d,0x13,0x82,0x85,0x27,0x5d,0x21,0x2f,0x38,0x36,0x11,0x70,0x50,0xc0,0xd7,0x33,0xaf, +0x3d,0xa1,0xcd,0xb9,0x75,0xe0,0x89,0x94,0xe6,0x96,0xfb,0xd4,0x94,0xd0,0x7e,0x04,0xc4,0x96,0x9d,0xb5, +0x6f,0xd4,0x53,0x6a,0xc3,0xf4,0xb6,0xfe,0x7c,0x26,0xe0,0x1e,0xd5,0x16,0xd8,0xd9,0x14,0x26,0xab,0x6f, +0x82,0x6a,0x5b,0xa9,0xb5,0x87,0x5f,0xf6,0x19,0xe9,0x97,0x0d,0xcd,0xec,0x11,0x18,0x16,0x0c,0xe0,0x74, +0x4a,0xbb,0x40,0xfb,0x29,0x9f,0x8b,0x77,0xcd,0x66,0x37,0x5a,0x82,0x35,0xc8,0x0f,0x6c,0x09,0xb4,0xdb, +0x55,0x3f,0x63,0x9c,0xc2,0xdb,0xcc,0x1d,0x98,0x94,0xa8,0x5b,0xc9,0x48,0x7d,0x7d,0x83,0x93,0xab,0xfd, +0x6e,0xf8,0x78,0xf0,0x3a,0x2a,0xaf,0x86,0xf3,0x8c,0x46,0xed,0x21,0x5f,0xbe,0x7d,0xe9,0x1d,0x1c,0x59, +0x06,0x7e,0x0e,0x7f,0xeb,0x48,0x08,0x99,0xdb,0xb0,0x39,0x2b,0xfd,0x6a,0x8c,0xe0,0x09,0x8b,0x69,0x76, +0x59,0xfa,0x1f,0x4a,0xff,0x63,0x29,0xae,0x6c,0xe2,0xca,0xba,0x81,0x8f,0xe9,0x06,0x8e,0xa5,0x00,0x44, +0xb9,0xa6,0x77,0x95,0x83,0xb4,0x60,0xa8,0x3d,0xd5,0x5c,0x9c,0xe5,0x87,0xf4,0x9d,0x7f,0x57,0x62,0x83, +0x86,0x75,0xed,0x9d,0xf3,0xd0,0x09,0xa6,0x9d,0x28,0x01,0xbc,0x51,0x32,0x33,0xca,0xdb,0x39,0xbf,0x33, +0x20,0x83,0x6e,0xaa,0x46,0xcf,0xd7,0x54,0x0f,0xcc,0x0d,0xc0,0xf7,0xcf,0xb6,0xbe,0xca,0x3d,0x68,0x1d, +0xe0,0xf5,0x20,0x17,0xca,0xf7,0x7b,0x4a,0x55,0x98,0x79,0x01,0xac,0xf4,0x8c,0xa7,0xcc,0xd8,0x96,0x23, +0x8e,0xd8,0x96,0xa2,0xa1,0xbb,0x84,0x82,0x30,0x9f,0xf9,0xdf,0x0d,0x75,0x53,0x68,0xa3,0x0e,0x6b,0x77, +0xec,0x6f,0x50,0x7b,0x62,0x30,0x16,0x4a,0xd1,0xed,0xa8,0x48,0x96,0xc1,0xf4,0xf7,0x59,0x75,0xdb,0xc4, +0x8c,0x98,0x7c,0x37,0xac,0x92,0x9a,0x1c,0x68,0xc1,0xd4,0x9e,0xeb,0x88,0x4d,0x72,0xfe,0x15,0xab,0x38, +0x5e,0xec,0x88,0x6b,0x04,0x80,0x80,0x36,0x08,0x89,0xc5,0xda,0x43,0xc0,0x1b,0xdc,0x69,0xfc,0xb3,0x80, +0x28,0x7b,0xc4,0x0e,0x2b,0x9b,0xc0,0x7d,0x8c,0x66,0xe7,0xeb,0xfd,0x38,0xa0,0x9e,0xe4,0x29,0x1b,0x48, +0x5a,0x83,0xb7,0x63,0x59,0x31,0xd3,0x0b,0x1b,0x25,0x92,0xe6,0x57,0x76,0x71,0x31,0xc9,0xcd,0x9e,0x1e, +0x8e,0x02,0xcd,0xe4,0x19,0x93,0x85,0xea,0x2d,0x7c,0xec,0xcd,0x0d,0xb8,0x10,0x35,0x45,0xd1,0xd4,0xc2, +0xce,0xc5,0x7e,0x3e,0xad,0x9e,0xcf,0x82,0x1d,0x69,0xcc,0x66,0xed,0xf9,0xb2,0x59,0xe6,0x82,0x56,0x80, +0xf0,0x62,0x7c,0xd1,0x13,0x26,0xc6,0x55,0xb7,0x8c,0xf7,0xe0,0xf9,0xf9,0x30,0x5b,0xd2,0xd1,0x3d,0xd4, +0x1d,0xe5,0x57,0x97,0x0d,0x6c,0x0e,0x1b,0xfe,0x0c,0x1f,0x71,0xe0,0xb2,0x6c,0xb9,0xa8,0x0e,0x19,0xe4, +0xa6,0xca,0x6c,0x22,0x2c,0xa8,0x17,0x38,0x93,0x5b,0xf1,0x9e,0x22,0xda,0x5c,0xb2,0xdd,0xf6,0x31,0x62, +0xc1,0x2c,0x2a,0x8f,0x9f,0x63,0x8f,0x37,0x71,0x23,0x82,0xf1,0x47,0xda,0x43,0x1c,0xa7,0x25,0xb4,0x13, +0xbc,0x52,0x63,0xd7,0x08,0x74,0xca,0xad,0x1f,0x2b,0x33,0x1c,0xf5,0x6e,0x17,0xcf,0x1a,0xb6,0x1c,0x81, +0x62,0x85,0x5b,0xc2,0x3d,0x2c,0x48,0xbc,0x0d,0xcc,0x12,0x11,0xe0,0x7e,0x67,0xe2,0xf3,0xd8,0xb3,0x0f, +0x9c,0x0d,0x90,0x65,0x6b,0x3e,0x3d,0x17,0xb4,0x2f,0x15,0x57,0x0e,0x78,0x9b,0x92,0x4d,0xfa,0x20,0xe8, +0x34,0xf3,0x09,0xa8,0x9c,0x78,0x1f,0x46,0x7e,0x02,0x07,0x11,0x19,0x29,0xb6,0x8c,0xad,0xac,0x5a,0x22, +0x45,0x35,0x48,0xf7,0xaa,0x44,0xe0,0x78,0xd8,0x78,0xb1,0xdb,0x2a,0x23,0x6c,0x1d,0xb7,0xa1,0x58,0x1c, +0x8e,0x35,0x4c,0x95,0x40,0xa3,0x20,0x0c,0x95,0xae,0x4d,0x27,0xd0,0x84,0x18,0xde,0xd8,0x60,0x13,0xa5, +0x84,0x45,0x83,0xfd,0x8d,0x55,0x2d,0x0b,0x23,0xa3,0xdb,0x20,0x47,0x2a,0x81,0x40,0xbb,0x96,0xde,0xaf, +0x06,0x4d,0x21,0x7d,0x0f,0x43,0xda,0x1c,0x78,0x19,0x56,0x37,0xb2,0xb1,0x46,0xe2,0x89,0xef,0x04,0xfe, +0x72,0xe5,0x81,0x4f,0x1f,0xb1,0x3d,0x91,0x71,0x01,0x63,0x93,0xa3,0xa8,0x9d,0xf0,0xda,0x38,0x78,0x56, +0x1f,0xfd,0x2f,0x89,0x1c,0x60,0x07,0xe2,0x44,0x28,0x00,0xfa,0x06,0x5b,0xb4,0xd2,0xcf,0x1b,0x4a,0x64, +0x7f,0x9f,0x5f,0xe9,0x95,0x05,0x7d,0x3d,0x3f,0xc0,0x1c,0x93,0x71,0x4d,0x15,0xf4,0x7f,0x2d,0x96,0xa6, +0x37,0x06,0x5a,0x7e,0xca,0xbb,0x50,0x07,0x04,0x89,0x8c,0x7e,0xe7,0x39,0xa9,0xba,0xd8,0x35,0xd8,0x1e, +0xf7,0xf5,0xab,0x9f,0xd6,0xba,0x0b,0xa0,0x3c,0x53,0xdd,0xb9,0x0e,0xf4,0x49,0xd5,0xad,0xf4,0xf5,0xac, +0xd1,0xd9,0xf9,0x44,0x87,0xfc,0x0c,0x04,0x36,0x31,0xd5,0x33,0x53,0xb0,0x10,0x6b,0x68,0x2e,0x53,0x09, +0xe7,0x94,0xa8,0xce,0x95,0x5f,0xcb,0xa9,0x08,0x4a,0xa8,0xb2,0xea,0xd8,0x52,0x3a,0xb6,0x94,0x8e,0x55, +0xaa,0x7b,0xf4,0x67,0x39,0x33,0x13,0x1e,0x53,0x8d,0x1f,0x54,0xfd,0xd9,0xe3,0x50,0xb0,0xaa,0x2f,0x4b, +0xee,0xcb,0x2a,0x70,0x5b,0xc4,0x3a,0xea,0x9c,0xbe,0xa0,0x01,0xc5,0x77,0x52,0xdb,0xda,0x8d,0xb5,0x51, +0xe9,0x59,0xaf,0x5b,0xb5,0xf5,0xea,0x62,0x1c,0xa1,0x0b,0x1c,0xdf,0xc1,0xde,0x42,0x3f,0xa0,0x0d,0x5a, +0xc2,0x1c,0x03,0x6d,0x73,0x91,0xc2,0x79,0x4e,0x5f,0xd8,0x07,0x96,0x0d,0xdc,0xad,0x88,0x40,0x44,0x2e, +0x6f,0xc3,0x64,0xa4,0xdd,0x46,0x88,0x2a,0xc8,0x96,0xda,0xd3,0xbe,0x82,0xc2,0x16,0xf0,0x2e,0xbe,0x40, +0xd9,0x5a,0x92,0x80,0x62,0x49,0x35,0x7c,0x96,0xdd,0xa4,0xc1,0x57,0xae,0x54,0xda,0xf3,0xf9,0xd9,0x77, +0x2b,0x3c,0xe1,0xfa,0xab,0x27,0xa7,0x02,0xdf,0x41,0x4f,0x55,0x2b,0x3d,0x1f,0x5b,0xf0,0xcb,0xb4,0x12, +0x82,0x4b,0x0e,0x5b,0x7e,0xfe,0x66,0x5d,0x5a,0x2f,0x38,0x23,0x79,0xa1,0xf2,0xa9,0xde,0xa9,0xec,0xfe, +0x40,0xa0,0x93,0xb8,0xbd,0xc1,0xeb,0x36,0x96,0x7a,0xb7,0x96,0xd6,0xc9,0x84,0x84,0x0e,0x54,0xce,0xba, +0x32,0x99,0xff,0xda,0x86,0x37,0x87,0x9f,0x75,0x5a,0xcd,0x5f,0x9e,0x17,0x97,0x4c,0xf1,0xb3,0xe1,0x3d, +0xcd,0x8f,0xd4,0x76,0x7c,0x8c,0x43,0x8c,0x93,0xcf,0x30,0xbe,0xb8,0x92,0xf5,0x9b,0x9a,0xb9,0x35,0x18, +0xd0,0xec,0x1a,0xeb,0x4f,0x78,0xad,0x32,0x15,0x49,0x93,0x10,0xb1,0xca,0xb5,0x21,0x93,0xa9,0xd2,0x75, +0x5c,0xdf,0x5f,0x4d,0x45,0x34,0x3d,0x63,0xe8,0xd0,0x28,0x67,0xfb,0x76,0xb9,0x65,0x13,0xda,0x0f,0xd1, +0x32,0x3c,0x7c,0x64,0x27,0xa8,0x35,0x0f,0xb6,0x8e,0x1f,0x78,0x9b,0xfc,0xc1,0xf5,0xcc,0x97,0xa8,0x4a, +0x3d,0x99,0xe8,0xeb,0x7c,0x9b,0x20,0x20,0x6a,0x7e,0x49,0x8c,0xc2,0x17,0xa3,0x11,0x0d,0x57,0x51,0x06, +0x47,0x74,0x61,0x08,0xe7,0xcf,0x47,0x23,0x7d,0x0e,0xd3,0x52,0x88,0x3e,0x36,0xe0,0x80,0x0d,0xda,0x18, +0x67,0x38,0xa9,0xd1,0x22,0x90,0xca,0x96,0x01,0xb6,0x98,0x54,0xed,0xf1,0xd6,0xb6,0xdf,0x0d,0xe7,0x5f, +0x83,0x8c,0x4d,0x99,0x00,0x6e,0xb5,0x41,0x49,0xb8,0x75,0xaa,0x44,0x79,0x53,0xed,0x44,0x06,0x69,0x42, +0x7a,0xf8,0x5d,0x6a,0x1f,0x31,0x53,0x75,0x04,0xf6,0xf1,0x7e,0xd0,0x10,0xe1,0x9b,0xe9,0x60,0x1e,0x2b, +0xc3,0xdf,0xca,0x23,0xc9,0xc0,0x77,0xbc,0x41,0x2c,0x0e,0x66,0xf0,0xd8,0xe7,0x0b,0xcf,0xe9,0x33,0xc1, +0x8c,0x88,0xe1,0x60,0x5f,0xa8,0x4b,0xff,0xbe,0x8a,0xaa,0xaf,0x43,0xa7,0x74,0xb4,0x91,0xb1,0x02,0x1e, +0x41,0x86,0x7c,0xf5,0xbd,0x4e,0x10,0x9a,0xc2,0xb4,0x12,0xee,0xb6,0xf4,0xcf,0x4b,0x13,0x6a,0x14,0xf8, +0x83,0x2f,0xd8,0xda,0xae,0x81,0xf3,0x83,0x17,0xf7,0x0b,0xc9,0x28,0x3d,0x12,0xed,0x94,0x41,0x29,0x43, +0xba,0xa7,0xf5,0x8c,0x3e,0x09,0xac,0x55,0x7d,0xb5,0x13,0xec,0xae,0x55,0xb7,0xba,0x8c,0xce,0x8a,0xf7, +0x4a,0xc7,0x3c,0x34,0x4b,0x99,0x28,0x94,0xe8,0xe7,0x08,0x3f,0x5e,0x0b,0x37,0xa3,0xda,0x49,0x6b,0x21, +0x76,0x31,0x71,0xc1,0x94,0x6a,0xd9,0x1b,0xdb,0x93,0x65,0x2a,0x0e,0x84,0x31,0x18,0x45,0x80,0xfb,0x50, +0xf5,0x86,0x92,0x09,0x35,0xcc,0x6f,0x44,0x98,0x65,0x41,0x45,0x60,0x07,0xd7,0x7a,0x8c,0xc9,0x6d,0xa9, +0x90,0x36,0xbc,0x3a,0x24,0x2a,0xef,0xf7,0x74,0xc1,0xcf,0xea,0x3d,0xc3,0x78,0xaa,0x49,0xa5,0x8a,0x49, +0x6c,0xc5,0x14,0x87,0xa8,0x57,0xaa,0x98,0xd2,0x03,0xbe,0xbd,0x1b,0xd7,0xb1,0x66,0xa8,0x31,0x7d,0x48, +0x2e,0x52,0xc9,0xe4,0xd2,0x64,0x22,0xc4,0x89,0x64,0xa1,0x11,0x01,0x39,0x83,0x3c,0x54,0x9e,0xa8,0x12, +0xb1,0x51,0x90,0x02,0xb9,0x82,0xb9,0x86,0x8d,0xcf,0x39,0xaa,0x9b,0xee,0x83,0x40,0x60,0x36,0xee,0x9a, +0xd0,0xb9,0x12,0x85,0xb9,0x36,0x4f,0xa9,0x06,0x32,0x7d,0x05,0x83,0x4f,0xa2,0x68,0x29,0x17,0x3d,0x75, +0x48,0xaa,0x39,0x6c,0x84,0x79,0x9d,0xe8,0x3b,0x0a,0xbc,0x50,0x2f,0x0f,0xd0,0x4f,0xac,0x4d,0xed,0x9c, +0x87,0xad,0x60,0x84,0xa0,0xa7,0x2b,0xc6,0x57,0x82,0x02,0x37,0x42,0x05,0x8b,0xa5,0x54,0x98,0x4c,0x89, +0xf3,0x9d,0x8d,0x3d,0x7b,0x44,0xa4,0x22,0x29,0xcf,0xd4,0xdb,0x96,0x20,0xc4,0xaf,0x6f,0x8a,0x4c,0x8f, +0x37,0x07,0x94,0xc6,0xa2,0xd1,0xac,0x54,0x38,0xf9,0xca,0x4b,0xa7,0x63,0x0e,0x09,0x26,0x9a,0xaa,0xf8, +0xc1,0xd9,0x4d,0xff,0xe0,0xd2,0xeb,0x24,0x33,0xce,0x4b,0xad,0x0e,0x33,0xa3,0x38,0xe6,0x67,0x75,0xfe, +0xb8,0x86,0x32,0xd6,0x98,0xc6,0x26,0xf4,0x2c,0x87,0x15,0x3a,0x67,0xf1,0x35,0xff,0x0d,0x13,0x43,0x84, +0xeb,0x5c,0x26,0x11,0xc7,0xce,0x53,0xef,0x33,0x18,0x0d,0x28,0x53,0xa0,0x1b,0x25,0x3a,0x11,0x53,0x78, +0xd9,0xf0,0x36,0x1a,0x87,0x68,0x23,0x0e,0x32,0x8c,0xbe,0x75,0xaa,0x12,0x46,0x1b,0xbc,0xc1,0xa3,0xc6, +0x16,0xb5,0x6a,0xfb,0x1f,0xb7,0xb7,0x28,0x91,0x6a,0xdd,0xbf,0x45,0x35,0x1c,0x99,0xef,0xdf,0xa2,0x14, +0xe5,0xa7,0xdd,0xf0,0x90,0xff,0xf3,0xe4,0x96,0xe3,0x9f,0xc5,0xb3,0xd6,0x56,0xd5,0xaa,0xe3,0x7f,0xb6, +0x55,0xed,0xed,0xda,0x78,0x78,0x27,0xd7,0x75,0xe0,0x93,0x55,0x8c,0xba,0x2d,0xf9,0xf4,0xac,0xb6,0xab, +0xfc,0xf1,0x4d,0x43,0xd4,0x63,0x7f,0x70,0x83,0x40,0x62,0xc6,0x32,0x5c,0xe9,0xd5,0x1f,0x9d,0x8b,0x85, +0x40,0xb7,0xb0,0xb6,0xb9,0x9d,0x38,0x94,0x9e,0x55,0xd0,0x96,0xc1,0xe7,0x84,0x95,0x66,0x2f,0xe9,0xe8, +0x23,0x6a,0x7d,0xe4,0x05,0x37,0x5a,0xd7,0x63,0xa2,0xb6,0x53,0x0f,0x9c,0xb6,0x1f,0xb2,0x2f,0x4b,0x1e, +0x5f,0x4c,0x46,0x08,0x5f,0xb9,0x95,0x6a,0x51,0xff,0xc0,0x2e,0x21,0xcb,0x1d,0x22,0x42,0xcb,0xeb,0xe5, +0x73,0xba,0xf2,0x9d,0xf9,0x32,0x2a,0x0a,0xd8,0x29,0xe0,0x17,0x1f,0x3b,0x18,0xbf,0xfa,0xb1,0x2c,0x9b, +0xb7,0x25,0xef,0xd4,0xc7,0xf5,0x8e,0x96,0xed,0x08,0x2e,0x59,0xd6,0xcd,0x6e,0x6d,0x9b,0x5b,0x9d,0x23, +0x77,0x98,0x2f,0x94,0x58,0x53,0x92,0xda,0x91,0x37,0xd4,0xcf,0x65,0xe3,0xe3,0x3f,0x5a,0x4a,0x93,0x5f, +0x51,0xa3,0x05,0x08,0xb3,0x38,0x5a,0xbc,0x49,0x97,0x88,0x91,0x75,0x1d,0xdd,0xbe,0xe2,0xb5,0x82,0x9e, +0x8a,0x97,0x4b,0x65,0x50,0xa3,0xee,0xde,0x8a,0xca,0x10,0x9f,0x64,0x37,0xf4,0x2a,0xc5,0xf3,0x6c,0xa9, +0xae,0xd6,0x45,0xfc,0x3a,0x02,0xdc,0x22,0x87,0x43,0xfc,0x8a,0x75,0x8a,0x9c,0x80,0xad,0xac,0xbe,0x5e, +0x88,0xfb,0xbb,0xcd,0x13,0xf1,0xe9,0x6f,0xa6,0x32,0xdb,0xae,0xd7,0x0e,0x51,0x66,0xf3,0x5a,0xba,0x3c, +0xaa,0xc4,0x09,0x06,0xef,0x7e,0x20,0x15,0x7f,0x2d,0x4a,0xbb,0xa6,0xec,0xce,0xdb,0xbd,0xd2,0x99,0xf1, +0x50,0x98,0x81,0xba,0x10,0xd7,0x8e,0xb2,0x5a,0xfa,0xdf,0x28,0x33,0x51,0xa2,0x50,0x76,0x19,0xec,0xca, +0xa1,0x51,0xda,0x42,0x55,0x08,0x44,0xc7,0x2a,0x5c,0xed,0x9a,0x0f,0x12,0x1c,0x36,0xe1,0x37,0x60,0xf8, +0xf3,0xb0,0x19,0x82,0xd6,0xd9,0x73,0xfa,0xdf,0x13,0x35,0x0b,0x20,0x09,0x0d,0x8b,0x32,0x1a,0x67,0x21, +0xed,0xab,0xfc,0xad,0x05,0xd9,0x4c,0x29,0x33,0x4e,0xc6,0x06,0xad,0x79,0x3f,0x94,0xbb,0x71,0x11,0x7e, +0xef,0x02,0xac,0x8c,0xd6,0x6d,0xa1,0x34,0x36,0x36,0x34,0x1d,0x2f,0x01,0xbf,0xf0,0xec,0xf0,0xb5,0x7a, +0x67,0xfc,0x9f,0xef,0x5a,0xab,0x9c,0xfb,0x7b,0xb7,0xd7,0xb2,0x12,0xae,0xb1,0x7f,0xd8,0x46,0x74,0x5b, +0x60,0x35,0xfe,0xff,0xd5,0x78,0x48,0x60,0xe2,0x8e,0x41,0xe1,0xf0,0x83,0x79,0x98,0x1b,0xa7,0x28,0xf3, +0xca,0xff,0xcf,0x47,0x49,0x58,0xe6,0xe6,0x28,0x59,0xda,0x03,0xd5,0x70,0x2d,0x91,0x6b,0x49,0x0e,0x6a, +0x18,0xfe,0x40,0xec,0x17,0x39,0x61,0x35,0xe1,0x95,0x08,0xa1,0x36,0x4c,0x1d,0x91,0xb2,0x3b,0x46,0x39, +0xb5,0x46,0xd9,0xaa,0x67,0x6d,0x94,0x53,0x3d,0xca,0xec,0x06,0x0f,0x80,0xef,0x7b,0x64,0x52,0x3c,0xe5, +0xea,0x03,0x1b,0x8a,0xb3,0x95,0x90,0x70,0xba,0x34,0x3e,0x57,0xeb,0xc3,0x5b,0xc2,0x8c,0x40,0xc6,0x16, +0xf8,0x61,0x52,0x11,0x22,0xbd,0x93,0x5a,0xc3,0x40,0x53,0x57,0x4d,0x2f,0x95,0x1c,0xb0,0x02,0x6e,0xa0, +0xbe,0xd2,0x1d,0x28,0xa6,0x53,0x34,0x91,0x4c,0xfd,0x19,0xf2,0xc9,0x00,0x82,0x3b,0x3f,0xff,0x6c,0xce, +0x94,0x9f,0x7f,0x76,0x8c,0x97,0xbf,0x3d,0xaa,0x4a,0xde,0xd9,0x39,0xd0,0x80,0x9c,0x15,0x3a,0xd1,0x71, +0x82,0x9a,0x00,0xb8,0x9e,0xb1,0xc7,0x70,0x64,0xe2,0xb3,0xa0,0xda,0xd5,0xbd,0x5c,0xc3,0x91,0x92,0x76, +0x61,0xda,0xc5,0x98,0x76,0x7a,0xce,0xe7,0x7a,0xce,0x37,0xa7,0xba,0x2b,0x73,0x1d,0x0b,0x41,0xa6,0xbb, +0x99,0xd5,0x25,0x66,0xb3,0x89,0xf6,0xad,0x26,0x57,0xef,0x50,0x93,0x78,0x27,0x44,0xb9,0x9d,0xe5,0xe2, +0x2d,0x68,0x6d,0xd5,0x44,0x96,0xef,0xda,0x4a,0xb4,0xfb,0x84,0x91,0x63,0x37,0xd6,0xfa,0x44,0x18,0x90, +0xda,0x9c,0xeb,0x12,0x5f,0x2a,0xe2,0x2a,0x19,0xb7,0x9c,0x7c,0xd8,0x34,0x28,0x9f,0xd4,0x27,0x9f,0x99, +0x9f,0x54,0x35,0xd7,0x23,0x02,0x5c,0xf1,0x34,0xc9,0x24,0x09,0x61,0x6d,0x60,0x6c,0xed,0xd4,0x6a,0xa1, +0xe7,0x7d,0xbc,0xa8,0xdb,0x7e,0x40,0x08,0xec,0x9a,0x90,0xbb,0x49,0x97,0xef,0x97,0x0e,0x64,0x4d,0xdf, +0x52,0xdf,0x3b,0x1c,0xab,0x05,0x1f,0x50,0xb9,0x96,0x15,0x81,0x02,0xe0,0x6a,0x3d,0xd7,0x94,0x4d,0xe3, +0x40,0x64,0xc5,0xb3,0xa2,0xe5,0x4a,0xdb,0xfd,0xbb,0x9a,0x86,0x89,0xef,0x30,0x33,0xc4,0xa6,0x7c,0x9c, +0x97,0xf0,0x46,0x09,0xa6,0x0c,0xcd,0xf6,0x89,0x5b,0xaf,0x46,0xd2,0x55,0x87,0xe4,0xde,0x0a,0x5c,0xb6, +0x2b,0x00,0x21,0x3f,0xcf,0xd8,0xaa,0x78,0x6f,0x92,0x06,0xf4,0x38,0x51,0x82,0x8f,0x4e,0x6b,0x20,0xbd, +0x31,0x9e,0x94,0xd8,0xc1,0x03,0x15,0x93,0x07,0x7d,0x06,0x74,0x79,0x25,0x34,0xab,0x93,0xd7,0xba,0x8e, +0x81,0x06,0xd9,0xfd,0x83,0xd4,0xa6,0xaa,0x95,0xed,0x88,0xdf,0x63,0xdd,0xfd,0xf7,0xae,0xf6,0xcd,0xe3, +0x60,0xe2,0x0a,0xfc,0x71,0x47,0xb6,0x3c,0x77,0xb1,0xd9,0x28,0x9b,0x09,0x62,0x99,0x9a,0xc4,0x5c,0x11, +0x2a,0x19,0xd2,0xc0,0xa0,0x47,0xb3,0x61,0xc3,0x3a,0x2c,0x98,0xc1,0x0f,0xa6,0x00,0x22,0x2c,0x26,0x51, +0xbf,0x8a,0x27,0x3b,0x96,0x2d,0x2d,0x3a,0x1e,0x4d,0x96,0x01,0xbd,0x0a,0x68,0x85,0x1d,0x2f,0xc5,0x32, +0x0a,0xd1,0x0a,0xd8,0x5b,0xd4,0xad,0x84,0x45,0x9b,0x4d,0x0e,0x6c,0x29,0x78,0x04,0xa5,0x06,0xad,0x0a, +0x28,0xfe,0xa9,0x4d,0xfe,0xe9,0x17,0x9b,0x4d,0x2f,0x71,0xed,0x37,0xb0,0x47,0x16,0x8c,0x5e,0x0e,0x17, +0xc1,0xce,0x9d,0x97,0xe0,0x65,0x65,0x55,0xf8,0x15,0x14,0xd0,0x78,0x2d,0x02,0xc9,0xd2,0x9c,0x42,0xeb, +0x76,0x6c,0x9c,0x9a,0xf3,0x09,0xab,0x8c,0x75,0xef,0x64,0xb2,0x44,0x74,0xc8,0x00,0x86,0xef,0x4f,0x8c, +0x95,0x14,0x84,0xfa,0xc4,0x55,0x80,0xa9,0x74,0xf3,0x8a,0xc8,0xb6,0xdc,0x75,0xac,0x39,0xa9,0xf2,0xe4, +0x49,0x96,0x7b,0x12,0x8f,0xd7,0x63,0xed,0x12,0x00,0xf9,0xf4,0xa8,0xb2,0xe3,0x7e,0x6d,0x3c,0x10,0xbb, +0x19,0x36,0xe9,0x75,0xea,0x57,0x09,0xcf,0x2a,0x81,0x5d,0x93,0x2a,0xad,0x2d,0xc7,0x59,0x9b,0xbb,0xe7, +0x5e,0x6b,0x19,0x84,0x19,0x61,0x85,0xf2,0xbf,0xae,0xb7,0x85,0x66,0x91,0xea,0x60,0xde,0x4d,0x81,0x09, +0x68,0xa4,0x84,0xc2,0x72,0xd4,0x4b,0x45,0x5b,0xbb,0x02,0x30,0x29,0x31,0x51,0x5d,0x70,0xe5,0xea,0x19, +0x3e,0x71,0xb2,0x94,0xf6,0x1c,0x25,0x02,0xf4,0xd4,0x06,0xfd,0xb5,0x62,0xad,0x15,0x7a,0x13,0xff,0x6c, +0x34,0xd2,0x12,0x63,0x33,0x89,0xd9,0x82,0x5a,0x66,0x97,0xca,0x71,0xd7,0x6f,0x63,0x2f,0xdd,0x07,0xda, +0x19,0x4e,0xf3,0xcd,0x26,0x8d,0x01,0xa1,0x39,0xd7,0xfb,0xae,0x2f,0xb2,0x1a,0x22,0x18,0x78,0x1d,0x00, +0xc0,0xc1,0x7e,0x69,0xd0,0x02,0x38,0x45,0x05,0xa4,0x57,0xc1,0x6d,0xd2,0x82,0x01,0x09,0x10,0x85,0x45, +0x98,0x87,0x9c,0xbf,0x0f,0xb6,0x39,0x6f,0xd8,0x8e,0xdb,0xf7,0xbd,0xaf,0x15,0x8f,0xb8,0xe8,0xeb,0x96, +0x54,0x90,0xb8,0x98,0x35,0x8b,0x8a,0x5c,0x1b,0x32,0xa1,0x46,0xcf,0xae,0xc2,0x85,0x55,0x2a,0x35,0xe1, +0xca,0xc4,0x8d,0xb8,0x52,0x90,0x9f,0xb0,0x31,0xb7,0x3e,0x0d,0x84,0xf0,0x46,0x87,0xf7,0x17,0x88,0x22, +0x54,0x43,0xec,0x2a,0xeb,0x10,0x3d,0x0b,0xbf,0x65,0x7d,0x00,0x1e,0x91,0x7d,0xe9,0x8a,0x53,0xa9,0x1c, +0x1d,0x43,0x47,0xc1,0x23,0xdf,0xea,0x87,0xd0,0xc2,0x90,0xa5,0xe7,0x15,0xd2,0x60,0x68,0x25,0x9a,0xfc, +0x87,0x90,0xa1,0x22,0xb0,0x29,0x35,0x58,0xa0,0x0a,0x1f,0x5a,0x2a,0x30,0x24,0x9c,0x1f,0x1a,0x54,0x29, +0x67,0x6c,0x6c,0xb5,0x3d,0xc3,0xe4,0xbd,0xb6,0xae,0x53,0x9f,0x65,0x0e,0xbb,0x81,0x50,0x13,0xda,0x82, +0x2e,0xf4,0x08,0x6c,0x36,0xe6,0xb2,0x72,0x2b,0x53,0x28,0x90,0x22,0x2b,0x4c,0x68,0x04,0x2f,0x86,0x1a, +0xcf,0x4c,0x1b,0x54,0xfc,0x40,0xfd,0x9e,0xdd,0x20,0x98,0x12,0xef,0x37,0xeb,0xb0,0x8e,0xac,0x0a,0x34, +0x55,0x3d,0xec,0xeb,0xfe,0x42,0x30,0x94,0x23,0x6b,0xd7,0xf3,0xc6,0xd1,0xb8,0xf1,0x44,0x81,0xd6,0xb2, +0xfb,0x52,0x34,0x06,0x60,0x19,0x0c,0x15,0x6c,0x47,0x33,0x4c,0x37,0x0f,0xd0,0xa5,0x9c,0xb0,0xb0,0xfd, +0xce,0x36,0x1b,0xed,0x65,0x28,0x35,0x23,0xfa,0xcd,0xdb,0x0a,0x10,0xc0,0x68,0x4c,0x65,0xaf,0xa6,0x99, +0xc2,0x94,0x2c,0x77,0x42,0x54,0x96,0x0a,0x65,0xe4,0xc9,0xe1,0x64,0x6d,0x41,0xc3,0xa2,0x2d,0x73,0x03, +0xed,0x19,0x35,0x71,0x3d,0xe5,0xab,0x99,0x01,0xc3,0x8d,0x34,0xde,0x28,0xcd,0x91,0x39,0xa0,0x1a,0xa5, +0x5b,0x23,0x48,0x13,0xe7,0x88,0x0d,0x1b,0x01,0xbc,0xb4,0x7a,0xb3,0xbf,0xff,0x26,0x76,0x71,0x7a,0xb8, +0x66,0xec,0x6b,0xdf,0x98,0xa7,0x4a,0x47,0xdf,0xc2,0x5b,0xaa,0x24,0x36,0x52,0xff,0x05,0x46,0xb8,0xec, +0xc0,0x70,0x82,0xbe,0xec,0xc2,0xd8,0x99,0x00,0xb7,0xd5,0x18,0x08,0x4a,0x79,0xd4,0xb1,0xac,0x23,0x4b, +0x35,0x6a,0x6b,0xef,0x4d,0xcc,0xb1,0xf2,0x96,0xcd,0xd8,0xcb,0x39,0xa0,0x5a,0x5b,0x73,0x81,0xe3,0xde, +0xe6,0x68,0x5e,0x01,0x0e,0x98,0x2e,0x24,0x92,0x9e,0xdf,0x5e,0xf7,0x54,0x4b,0xe4,0xe1,0x76,0xbe,0x53, +0x73,0xdf,0x64,0x52,0x78,0x55,0x37,0x80,0x28,0x50,0xb0,0x4b,0x3b,0x4c,0x25,0xaa,0x8d,0xd3,0x5e,0xf2, +0x08,0xe0,0xc2,0x5b,0x5e,0x5c,0x07,0xc9,0x1a,0x6d,0xbd,0x71,0xb3,0x0a,0x58,0x03,0xbc,0x18,0x3b,0x62, +0xb4,0xb4,0xb6,0xe0,0x26,0x4a,0xdb,0x6e,0xe8,0x12,0x9d,0x3b,0x6a,0x6b,0xdc,0xc8,0xd5,0xc3,0x17,0x0a, +0xfb,0x7a,0x97,0x0d,0x1a,0x88,0x73,0xcb,0xb3,0x60,0xaf,0x33,0xd3,0x94,0x11,0x14,0xac,0xb3,0xd5,0xc1, +0x61,0xb2,0xc7,0x27,0xcb,0x9e,0x3a,0x6c,0xf6,0xf4,0x39,0xb3,0x47,0xfd,0x99,0xfc,0x1e,0xef,0x89,0xfd, +0xe0,0x1e,0x03,0xf0,0xed,0x2d,0xce,0x97,0x72,0xc1,0xa0,0x42,0x80,0xf4,0x95,0xab,0xf5,0x4a,0x7e,0xc1, +0xac,0xed,0x19,0x1c,0xa2,0x3d,0x0d,0x3d,0xb4,0x57,0xc1,0x14,0xed,0x55,0xd0,0x44,0x7b,0x02,0x59,0xb5, +0xa7,0x82,0x2e,0x14,0xeb,0xf3,0xeb,0xa4,0xdc,0xfb,0x35,0xfe,0xc8,0xf9,0xd2,0xef,0x0a,0xc1,0x61,0x70, +0x41,0xd9,0x5b,0x38,0xf4,0x8e,0x65,0x98,0xde,0xa9,0x8b,0xae,0x4b,0xcd,0x2b,0xd1,0x7e,0x4b,0xc6,0x3c, +0x12,0xc6,0x58,0x0e,0x4a,0x71,0x76,0xd6,0x36,0xbb,0xba,0xdf,0xba,0xc6,0xf8,0x0a,0x8d,0xbb,0x67,0x84, +0xab,0xd6,0x82,0x8a,0xa8,0x1a,0x0c,0xa8,0x6b,0xb1,0x7e,0x23,0x5a,0x42,0xf5,0x77,0x48,0x07,0x92,0x46, +0x69,0x04,0x7e,0x8e,0xf5,0x4a,0x19,0x6f,0x43,0xff,0x2f,0x08,0x91,0x06,0xce,0x51,0xd0,0x1c,0x6d,0xf0, +0xc5,0xae,0x79,0xd1,0xd0,0x59,0xab,0xcd,0x5e,0x4d,0x6d,0x68,0xe2,0x35,0x90,0x9e,0x79,0x29,0x30,0xc6, +0xde,0x76,0xdc,0x3a,0x1b,0x4a,0x21,0xab,0xd6,0x96,0xb4,0x5c,0xaf,0x27,0xe9,0xc2,0xfa,0x3e,0x2c,0xdc, +0x8d,0x15,0x91,0x2a,0x87,0x56,0x98,0xf6,0x9d,0xbc,0x8d,0x7a,0x1e,0xcb,0xbc,0xf4,0x6b,0x89,0x39,0x66, +0xf7,0xc8,0xeb,0x1f,0x32,0x98,0x87,0xa0,0x47,0xff,0x37,0x8a,0x1e,0x1c,0x8e,0x93,0x49,0xbd,0x80,0x04, +0x01,0xc3,0x3b,0xf1,0x16,0xad,0x0a,0x29,0x28,0x14,0x64,0xc1,0x1e,0x27,0x4c,0x9e,0xfd,0x0a,0xf9,0xd4, +0x32,0x9b,0xf3,0xf9,0xe0,0xbf,0xaf,0x0c,0x11,0xfc,0x6f,0xc1,0x59,0x4f,0x98,0x36,0x63,0xe1,0xf8,0x8f, +0xaf,0x5f,0xb5,0xdd,0xa3,0x59,0x5a,0x06,0xd0,0xf3,0xa6,0xfd,0x95,0x01,0x38,0xc5,0x54,0x64,0xdf,0xff, +0x34,0xe4,0x3d,0x2a,0x1e,0x3e,0x7b,0xf3,0xfa,0x2d,0x32,0xcc,0x3d,0xc9,0xf8,0x79,0x9e,0x5d,0xbf,0xe7, +0xcf,0x99,0x66,0xa3,0x89,0x79,0x70,0x7b,0xbd,0x74,0x74,0xd8,0xf2,0xdc,0xa3,0x4f,0x15,0x47,0x56,0x39, +0x5c,0xf7,0x98,0x20,0x57,0xfa,0xea,0xe2,0xab,0x8f,0xa7,0xd1,0x25,0xb8,0x46,0xd7,0xe1,0x2c,0xf3,0x18, +0x31,0x85,0x1d,0xcf,0x36,0x8b,0x88,0x25,0x34,0xfc,0xcb,0x94,0xe8,0x53,0xca,0x8c,0x9a,0xc3,0x01,0x7f, +0xa1,0xf6,0xe2,0x9e,0x78,0x86,0xf6,0x4e,0xcf,0x66,0x0f,0x0e,0xfc,0x5f,0x58,0xa8,0x30,0x39,0x4b,0x0f, +0x2e,0xfd,0xa7,0x8a,0x7e,0x95,0x15,0xad,0x94,0x46,0x9b,0xe4,0x3a,0xba,0x8c,0x37,0xb4,0xa4,0x89,0x5a, +0xb9,0x48,0x96,0x31,0x6b,0x91,0x7e,0xbb,0x57,0xdd,0x44,0x4b,0xff,0x32,0x4e,0x3d,0x51,0x2d,0x31,0x18, +0x53,0xd8,0x31,0xd1,0xb5,0x13,0xfd,0x0e,0xf3,0x9d,0x46,0xd8,0x71,0x84,0xa6,0x19,0xe7,0x53,0x6d,0xff, +0x34,0x0b,0xe3,0x74,0x4e,0xe4,0xc5,0x77,0xef,0x5e,0xc2,0x45,0x9b,0xd8,0x40,0x06,0x6c,0xed,0x3b,0xa1, +0xd3,0xef,0x78,0x53,0xe3,0x7a,0xb7,0x6d,0x47,0x93,0x98,0xbd,0x85,0x7e,0xf9,0x0d,0xf1,0x92,0xf5,0xf9, +0xf7,0x76,0x19,0x25,0xa9,0x31,0x39,0xf4,0xf4,0xa2,0x8e,0x6d,0x2e,0x46,0xb0,0x4f,0x25,0xd4,0x5f,0x25, +0x08,0x00,0x43,0x60,0x8c,0xdd,0x52,0xc1,0xd7,0xfa,0x27,0x51,0x70,0x31,0x70,0x8c,0x31,0x85,0x8d,0xce, +0x4f,0x91,0x8f,0xfb,0x8e,0xd7,0xb4,0xbf,0xa4,0x91,0xa5,0x05,0x4c,0x3b,0x79,0x87,0x0b,0xb0,0xee,0x55, +0x1d,0xfa,0x53,0xa5,0x94,0xa6,0x78,0x6c,0x27,0x6f,0x3f,0xea,0x72,0x22,0xbe,0x6a,0x43,0x77,0x88,0x25, +0x87,0xd6,0xcd,0x8b,0x58,0x2c,0x56,0xb3,0xae,0x62,0xea,0x59,0x7b,0x5f,0x91,0xa5,0x4a,0x92,0xb9,0xf5, +0xb4,0x2d,0x68,0x2b,0x43,0x23,0x83,0xa9,0x39,0x72,0xa0,0xc7,0xb8,0xa3,0x95,0xa8,0x28,0x29,0x88,0xd4, +0xd7,0xcc,0x34,0xbc,0xc9,0x7e,0xd3,0x1e,0x89,0xb6,0xa8,0x06,0xb4,0xc9,0x53,0x0b,0xab,0x43,0xde,0xce, +0x35,0x24,0x55,0xef,0x3b,0x8d,0xcf,0xc7,0x91,0xe7,0x6b,0xed,0xab,0x4d,0x2e,0x5b,0x3e,0x55,0x87,0x0d, +0x14,0x03,0x81,0xa0,0x15,0xa6,0x4f,0x89,0xa1,0xd2,0x0e,0x31,0xd4,0x1d,0xda,0x12,0x08,0xab,0xa0,0x50, +0x87,0x2b,0x8c,0xae,0x5f,0x68,0x9d,0x03,0x74,0x0c,0x98,0xb6,0x5e,0xd0,0x91,0x34,0xed,0x4e,0x2a,0x10, +0x10,0x26,0xd6,0x38,0x2d,0xb7,0x3f,0x1f,0x8d,0x68,0x8d,0xbe,0xa0,0xab,0x3f,0x0d,0x1f,0xd2,0xca,0x7d, +0x4e,0x57,0xee,0x74,0xb2,0x3f,0xf3,0x7e,0x0e,0xa7,0x3f,0xed,0xcf,0x1e,0x1e,0xf8,0x6f,0x78,0x55,0x0e, +0x1f,0x4e,0x88,0x9f,0xdb,0x3b,0x2b,0x67,0x0f,0xdd,0xe9,0x4f,0xc8,0x11,0x11,0xbb,0x0e,0x2e,0xaf,0xfd, +0xb7,0x5a,0xf7,0x7b,0x4e,0xa7,0xcf,0x86,0x88,0x43,0xfc,0x1b,0x14,0x65,0x96,0x63,0x89,0x0f,0xfb,0x03, +0x9e,0x7c,0x05,0xb5,0x8e,0x57,0x3a,0x16,0xfd,0xe6,0x26,0x59,0x30,0xdc,0x2a,0x95,0xf8,0x4e,0x7d,0xfe, +0xcd,0xd7,0xa7,0x9b,0x17,0x5f,0x3f,0x7d,0x06,0xb3,0xfc,0xd7,0x8c,0x73,0x76,0x70,0x76,0x70,0xe0,0xbf, +0xe4,0xf0,0xc1,0x3f,0xf0,0xdf,0x07,0x65,0xe8,0x3c,0x3c,0x70,0x00,0x2c,0x46,0x5b,0x9b,0xeb,0x3c,0x44, +0xb0,0xb0,0x2e,0x53,0xa0,0x88,0x66,0xd6,0x57,0x25,0x2b,0x16,0xc3,0x5f,0xe5,0xb7,0x66,0x93,0x32,0x07, +0xe8,0x43,0x30,0xf2,0x11,0x23,0xe7,0x75,0xb6,0x48,0x2e,0x12,0xa2,0xee,0x60,0xc7,0x5b,0x46,0x97,0x1c, +0x9c,0xe6,0x97,0xe8,0xf6,0x7d,0x5c,0x96,0xb4,0xa5,0x16,0xc1,0xdd,0x3a,0x5f,0x06,0x3a,0x17,0xa6,0x0a, +0x1d,0xaa,0xab,0x43,0x94,0xe1,0x2b,0xda,0xf6,0x97,0xc1,0x5b,0x35,0x75,0x7e,0x55,0x8e,0x31,0xf3,0x0c, +0x44,0xac,0x04,0xba,0x01,0x5c,0x65,0x9e,0xe1,0x98,0x61,0x74,0x2f,0xba,0x8d,0x8a,0x8f,0xe9,0x5c,0xa1, +0x4c,0x43,0xbb,0x26,0xc8,0xc9,0x20,0xa9,0x13,0x39,0x43,0x0e,0x6e,0x07,0x37,0x37,0x37,0x03,0x5a,0xe4, +0xd7,0x03,0x2a,0x59,0xb6,0x9d,0xc5,0x18,0xf4,0x51,0x0e,0x1f,0xb9,0xef,0x4e,0x9f,0x0f,0xfe,0xea,0x70, +0xe8,0xdf,0x55,0xa9,0xbc,0x11,0x1e,0x94,0x02,0x72,0x25,0x9b,0xff,0x0a,0x5b,0x8c,0x23,0xb8,0x38,0xf2, +0x04,0x97,0x8e,0x7f,0x8b,0xfb,0x5a,0x49,0xd7,0x4b,0x7f,0xcf,0x9c,0x17,0xfe,0x2f,0x05,0xbb,0xf0,0x5b, +0x09,0xf0,0x44,0xa5,0x40,0xbc,0x2c,0x85,0x59,0xb6,0xd5,0x75,0xa7,0xd2,0x91,0xe7,0xc1,0xd9,0x39,0xfd, +0x9c,0x9d,0x1f,0x48,0x91,0x74,0x8b,0xdf,0x03,0xc9,0x8f,0xee,0xf0,0x4b,0x6f,0xa1,0xa7,0x2a,0x68,0xe7, +0xa4,0x03,0x2b,0x89,0x97,0x0b,0xf5,0xb1,0xa3,0x1f,0xd2,0x79,0xe2,0xa8,0x56,0xe8,0x47,0x40,0x6d,0xd0, +0xd5,0xd2,0xcf,0xfe,0xf6,0xfe,0xcd,0xb7,0x52,0x03,0x22,0xbb,0x4a,0xe5,0x8f,0xc1,0x55,0x74,0x02,0x39, +0x04,0xe5,0x08,0xdc,0xe3,0x36,0x33,0x4a,0x29,0xdf,0x22,0x17,0x27,0xc0,0xd7,0x72,0x68,0xaa,0xc7,0x68, +0x78,0x60,0x9d,0xd0,0x44,0x3c,0x11,0x41,0xf4,0x46,0xa4,0x60,0x32,0xf4,0x7a,0xac,0x6e,0xe1,0x74,0xbf, +0x35,0x93,0x63,0xbd,0xc3,0x9e,0xa1,0x9c,0xfc,0xdd,0xfd,0x3b,0x3d,0x81,0x91,0x91,0x35,0x8d,0x20,0x3a, +0x0a,0xfe,0xee,0x36,0x9e,0x32,0x3e,0x19,0x1e,0x54,0xe0,0x7c,0xff,0x70,0x5f,0x42,0xda,0x46,0xcf,0x4e, +0xf3,0x28,0xa5,0x46,0xe7,0x25,0x3d,0xfb,0x41,0x3d,0xab,0x49,0x73,0x2c,0x0c,0x94,0x5c,0x49,0x77,0x0a, +0xd9,0x8e,0x96,0x1c,0x86,0xe5,0xdc,0xbf,0xf1,0x4f,0xc3,0x74,0x3c,0x47,0x7c,0x18,0xd8,0x15,0xae,0xa1, +0x6e,0xaf,0x99,0xde,0xad,0xe1,0xfe,0xa8,0x58,0xa8,0x28,0x2c,0xa0,0xa1,0xf0,0x4f,0xac,0xf8,0xf0,0x61, +0x49,0x74,0xf1,0xe7,0x58,0x2a,0x74,0x15,0x1e,0x8d,0x46,0xc4,0x54,0x1e,0x3f,0x1a,0x8d,0x36,0x9b,0x47, +0xa3,0xcf,0x21,0xb7,0xf7,0x11,0xb5,0xe0,0x3c,0xfc,0x97,0x7b,0xe5,0x9f,0xb0,0xf3,0xf5,0x79,0x18,0xc7, +0x74,0x73,0x4e,0xb7,0xb4,0x0e,0x96,0x13,0xf7,0x6a,0x98,0x5c,0xe8,0x45,0x46,0x69,0x6f,0xc2,0x13,0x6c, +0x43,0xef,0xd4,0x78,0xbe,0xa0,0xa2,0x10,0x13,0xfe,0x15,0x2d,0xc5,0x81,0x4e,0x46,0xeb,0xfa,0x46,0x70, +0x7e,0xec,0x15,0x8a,0xa8,0x77,0x37,0xf4,0xa6,0x3b,0x03,0xac,0xdd,0xea,0x3b,0xdc,0x49,0x7a,0xcf,0x3f, +0x92,0x9a,0x52,0xdb,0xb0,0xbf,0x40,0xb0,0x7b,0x25,0x18,0xd8,0xa7,0xa1,0x93,0x66,0x6a,0x2e,0x3b,0x81, +0x6a,0x90,0x3c,0x2d,0xaf,0x75,0x55,0x02,0xf7,0x34,0x3c,0x87,0xb5,0x66,0x19,0xfb,0x2b,0xba,0xe2,0xe0, +0x0f,0x0b,0xba,0x60,0x7a,0x88,0xfa,0xa5,0xb7,0xf0,0x88,0x7a,0x5c,0x84,0xa7,0x3e,0xcc,0xbd,0x4f,0xa9, +0xaf,0x29,0x07,0xa1,0x9f,0xfc,0x92,0xd5,0xbb,0x65,0x38,0x42,0x70,0xf2,0x13,0xce,0x65,0x0d,0x37,0x4b, +0x7d,0xc9,0xb8,0x24,0x2e,0x11,0xf7,0xa7,0x44,0x64,0x38,0xd4,0x5b,0x1f,0x6b,0xa1,0x20,0x2f,0xfd,0xe9, +0xca,0x3f,0xf5,0x4f,0x66,0x5e,0x80,0x17,0x20,0x1a,0xf4,0xf3,0x13,0x7a,0x4e,0x6c,0xb5,0xc9,0x09,0xf8, +0xb2,0xee,0xad,0xe7,0xdf,0xea,0xd1,0xbc,0xd8,0xdf,0xff,0x60,0x18,0x97,0xe5,0xc4,0xe1,0x69,0xb7,0x66, +0x92,0xd7,0x09,0xf8,0xee,0x6b,0xa9,0x23,0x65,0x75,0x45,0x25,0xaf,0x02,0x64,0x77,0xcd,0x21,0x51,0xad, +0x42,0x20,0x1d,0xa2,0x26,0x54,0x59,0xf1,0xa7,0x27,0xca,0x6d,0x44,0xbe,0xa6,0x34,0x83,0x01,0x66,0x36, +0xef,0xab,0x42,0x2c,0xd6,0xf8,0x4d,0x29,0xbc,0xcc,0x58,0x6a,0xbd,0xed,0x92,0xa6,0xb5,0x40,0x3e,0x53, +0x0e,0x6e,0x62,0xe1,0x0b,0xd4,0x03,0x0c,0x85,0xd5,0x42,0x5a,0xaf,0xe0,0x82,0x91,0xd2,0x9e,0x1b,0x5e, +0x0d,0xd5,0x4a,0xdd,0x6c,0xae,0xfc,0x0f,0xd5,0x2d,0xe6,0x84,0x8d,0x21,0xa9,0x68,0x32,0x8e,0x3c,0x78, +0xc9,0x1a,0x52,0x91,0x99,0x7e,0x6c,0xc4,0xef,0xbc,0xc6,0xfd,0xae,0x00,0xae,0xd4,0xd5,0x57,0x56,0xe7, +0xb3,0xb8,0xec,0x1c,0xc7,0xd4,0x0d,0xfe,0xd0,0x1c,0x10,0x48,0x66,0x44,0x92,0x3b,0x09,0xef,0xaa,0x25, +0x15,0x70,0xc0,0x84,0xfa,0xf4,0xed,0xf0,0x90,0x24,0x6a,0x72,0x2e,0x42,0x35,0x01,0x69,0x44,0xac,0xb1, +0x71,0x19,0xbe,0x51,0x41,0x8f,0x22,0x84,0x33,0x99,0x96,0x6d,0xf8,0xb0,0xb0,0x9c,0x1e,0x41,0x89,0x0a, +0x9f,0xc2,0xfa,0x9b,0x6d,0x8d,0x26,0x29,0x85,0x26,0x29,0x39,0x54,0xfd,0xd3,0xe5,0xb2,0x5e,0xa1,0xa2, +0x83,0xbc,0x9b,0x2b,0x43,0x31,0xd6,0x23,0xbc,0x83,0x43,0x43,0x51,0xb6,0xaa,0x6f,0xed,0x84,0x52,0xce, +0x9c,0xfd,0x18,0x6e,0x5a,0xb5,0xe9,0x78,0x84,0xd0,0x9d,0xe7,0x30,0x1e,0x57,0x1a,0xd8,0xad,0x0f,0xde, +0x3a,0x4f,0x16,0xf1,0x6b,0xda,0xae,0x24,0x08,0xd3,0x2e,0xa1,0x3a,0x8a,0xb9,0x1a,0x5e,0xab,0x74,0x61, +0xac,0x73,0xa8,0x06,0xa8,0xbb,0x8f,0x63,0x8f,0x3b,0xfa,0x64,0x18,0x2d,0x6f,0xa2,0x8f,0x85,0x1b,0x4f, +0xf5,0x8a,0xb2,0x7d,0x4b,0x4a,0x21,0xb7,0x61,0xb6,0x15,0x4e,0x6f,0xd9,0xa0,0x9c,0xfe,0xd4,0xbc,0x88, +0x69,0x1f,0x3f,0xc7,0x5e,0xdd,0x61,0x08,0x44,0xcb,0xdb,0xc2,0x2e,0x4e,0x86,0x9c,0x10,0x3a,0x95,0xdc, +0x1d,0x69,0x6d,0xf3,0x96,0xf9,0x87,0x8f,0x26,0xe6,0xea,0x09,0x64,0xd7,0x74,0xfc,0x84,0x2e,0x04,0x05, +0x7c,0xb9,0xd9,0x28,0x2a,0x04,0x7b,0x85,0x67,0x28,0xbc,0xd7,0xa5,0x6f,0x91,0x1e,0x7d,0xe7,0xe0,0xc0, +0xc1,0xb7,0x2c,0xde,0x4b,0x87,0xd7,0x71,0x79,0x95,0x2d,0x60,0xf1,0x2e,0x31,0x52,0xae,0xcc,0x13,0x49, +0x42,0x29,0xb1,0xa3,0xa1,0xd3,0x8a,0xd0,0xad,0x6e,0x68,0xb7,0x24,0xf2,0xaa,0x3e,0x40,0xad,0xb0,0x5c, +0xd2,0xf5,0xb4,0xcc,0xf2,0x8c,0x28,0x9c,0xec,0x9a,0xe8,0x0e,0xef,0x6e,0xb9,0x83,0x20,0x03,0x0f,0xbb, +0x14,0x9a,0x8c,0x9b,0xe3,0xab,0x1b,0xf9,0xf1,0x6b,0xb9,0x84,0x5f,0x35,0x5a,0xd4,0x07,0x39,0x97,0x15, +0x65,0x0f,0xd1,0x61,0x6a,0x2f,0x96,0xfc,0x5c,0xf1,0xba,0x5f,0x7b,0x77,0xf5,0x7c,0x70,0x62,0x53,0xbf, +0x4a,0xbb,0xf6,0xf7,0xaf,0x86,0x16,0x39,0x56,0x99,0x53,0x18,0xae,0x5b,0xa7,0x53,0x1f,0x84,0x86,0x27, +0x92,0x7b,0x74,0x2b,0x14,0x50,0x18,0xdf,0x68,0x49,0x5b,0xfa,0xdf,0xe8,0xb0,0xa6,0xdd,0x33,0xf5,0x69, +0xb8,0xe6,0x9a,0x63,0x3f,0x19,0x57,0xf2,0x74,0x14,0x29,0xb4,0x20,0xb6,0xd1,0x91,0xa0,0x63,0xc8,0x3e, +0xd9,0xef,0xb7,0xc3,0xfe,0xe9,0x9d,0x32,0xca,0xcb,0x6a,0x10,0xe5,0x87,0x86,0xe2,0xbb,0xd5,0x4a,0x0f, +0x05,0xbd,0x83,0x0d,0x81,0x82,0x5e,0xec,0xbd,0x53,0x34,0xa8,0x24,0x85,0x55,0x05,0x77,0xb1,0x99,0x23, +0x2f,0x58,0x4d,0x5b,0xfb,0x68,0xb2,0xa3,0x4f,0x18,0x21,0x46,0xed,0x9c,0x42,0x9e,0x4a,0x14,0x35,0xa3, +0x3b,0xf9,0x24,0xad,0xca,0xb0,0x1d,0xaa,0x03,0xe5,0xc7,0xd4,0xe3,0x15,0xd5,0xa3,0xef,0xc8,0x79,0x29, +0x35,0x94,0x48,0x35,0x5a,0x9d,0xea,0xf9,0x66,0x04,0xb2,0x7e,0xe8,0x7e,0xab,0x9a,0x95,0x79,0x13,0xe2, +0x66,0x03,0x67,0xe2,0x78,0x7d,0x35,0x12,0xca,0xb4,0x53,0xee,0xf0,0xd9,0x9c,0xd8,0xe8,0x58,0x63,0x43, +0x67,0x61,0x66,0xca,0x7c,0x4e,0x65,0x3e,0x38,0x64,0xbd,0x50,0x67,0x86,0xce,0xcf,0xc4,0xdd,0xbf,0x2f, +0xfb,0xfd,0xbd,0xfe,0x42,0x2f,0xba,0x4c,0x2e,0x6b,0x84,0x4b,0x9b,0x1a,0xd9,0xdf,0x3f,0x19,0x36,0xb7, +0x42,0xd7,0x79,0x79,0x61,0xe8,0x98,0xc1,0xfb,0x84,0x8e,0x00,0xc7,0x6f,0x7f,0x2a,0x62,0x57,0x21,0x52, +0x76,0x66,0xf3,0x6d,0x96,0xc6,0x70,0x8b,0x9e,0x5f,0x39,0x56,0x72,0x9a,0x76,0xd6,0x7c,0xae,0x06,0x14, +0x77,0xd6,0xa8,0x29,0xa9,0x7c,0x6a,0x3f,0xf3,0xba,0x8b,0x52,0x19,0x0c,0x4e,0xd9,0x34,0xbb,0x96,0x0b, +0x13,0x18,0xad,0x0f,0x9e,0x32,0xf3,0xe1,0xd8,0x7b,0x07,0x47,0xec,0xbe,0x1a,0x2a,0xb6,0x64,0x5a,0x7f, +0x33,0x9b,0xec,0x7c,0xd3,0x07,0x1b,0xd7,0x0b,0xc3,0xfa,0xe3,0x89,0xe3,0xef,0x39,0xfd,0x07,0x65,0xdf, +0x19,0xef,0xfd,0x16,0x8e,0x86,0xa3,0x43,0x1a,0x2c,0xc7,0x0b,0xaa,0x6c,0xd8,0x03,0x9a,0xb5,0xef,0x2b, +0xec,0xcd,0xd4,0x11,0x72,0x6e,0x79,0x1d,0xf5,0x5d,0xf9,0xe6,0xf5,0x74,0x25,0xe8,0xcf,0x57,0x43,0xc1, +0x73,0x7c,0x4f,0x0c,0x21,0xcf,0xd6,0xea,0x56,0x14,0x9c,0x97,0x44,0xbf,0x5e,0x49,0x0c,0xae,0xcd,0x66, +0x6e,0x14,0xc4,0x27,0x6a,0xf3,0xe6,0x4c,0xe8,0x8c,0xe7,0x3b,0x87,0xc8,0x26,0x04,0xd0,0xbe,0x32,0xee, +0xb4,0xe8,0xb6,0x05,0x30,0x19,0x89,0x42,0x10,0x9a,0x0b,0x4f,0x2e,0xa2,0x64,0x49,0x4f,0x98,0x36,0x04, +0xdd,0xfd,0x37,0x22,0xeb,0xd5,0xee,0xc1,0x27,0x7d,0x8d,0xf0,0x3e,0xac,0x53,0x70,0xb2,0x31,0x30,0x2e, +0xa5,0x22,0xb9,0xac,0xfd,0x86,0xba,0x05,0x6c,0x25,0x06,0xa0,0x14,0xc2,0x1e,0x78,0xd3,0xee,0xba,0xee, +0x8c,0x63,0x9d,0xe8,0xba,0x19,0x8e,0x4a,0x0e,0x49,0x91,0xf9,0xd6,0x93,0xbd,0x7a,0x0e,0x87,0x46,0x18, +0x1a,0x13,0xcb,0x7c,0x0e,0x2f,0x2d,0xb3,0xc5,0xf2,0x89,0x59,0x5e,0xe5,0xd9,0xcd,0xde,0xd7,0xe3,0xdc, +0x1d,0x1c,0xfa,0x5f,0x7b,0x5b,0x89,0xc5,0xc7,0x77,0xce,0xb7,0xd9,0x9e,0x61,0x5e,0x2a,0x21,0xcf,0x09, +0x93,0x1a,0x60,0xc1,0x76,0x99,0xdb,0x5f,0xc6,0xda,0x50,0x99,0x3a,0xc5,0x61,0x96,0x8d,0x45,0x58,0xe5, +0x7b,0xe6,0x3c,0xbb,0xc9,0x0c,0xf3,0x91,0xd6,0x82,0x56,0xe0,0xda,0x75,0xd3,0x01,0x58,0xbf,0xf8,0x0e, +0x82,0xfe,0x74,0x60,0x35,0x35,0xf5,0x04,0x35,0x77,0xbe,0xba,0xe0,0x30,0x15,0x1b,0x22,0x08,0xb0,0xe1, +0x6c,0xe9,0xa7,0x86,0x6c,0x55,0x44,0xa9,0x6b,0xc9,0x1a,0xc0,0x41,0xc6,0xbe,0xd2,0x9f,0xeb,0x29,0x1e, +0x24,0x12,0xc6,0x34,0xf5,0xd5,0xec,0x08,0xc4,0x53,0xba,0x29,0x1e,0x84,0x0d,0xa4,0x6e,0xc4,0xcf,0xf1, +0x87,0x68,0xf9,0x1d,0xed,0x4d,0x1d,0x24,0x90,0x2e,0xd7,0x2e,0x4d,0x84,0x14,0xa6,0x44,0xdd,0x27,0x3e, +0xef,0x93,0x96,0x24,0xe2,0xd0,0xc8,0x2a,0x68,0xe0,0x78,0x50,0x0b,0x87,0x35,0x5d,0x4d,0xd9,0xe1,0x4d, +0x1e,0xad,0x80,0x70,0xba,0x13,0xcc,0x43,0xa9,0x9e,0x64,0xab,0x6c,0xb8,0xdd,0xc3,0x95,0xb5,0x32,0xe7, +0xa2,0x54,0xca,0xaa,0x4a,0x01,0xa9,0xd0,0x83,0xba,0xe8,0xde,0x1b,0xc6,0xbf,0xb9,0x3a,0x5c,0x32,0xbb, +0x83,0xea,0x64,0x75,0x9b,0xe9,0x1a,0x04,0xb2,0xce,0xda,0x2f,0x9b,0x52,0x48,0x03,0x7a,0x2c,0x31,0xe6, +0x62,0xc1,0x83,0x56,0xe4,0x09,0x7b,0x89,0x8d,0x3d,0xd4,0xb0,0xfd,0xd8,0x40,0x57,0x18,0x30,0x5c,0xb1, +0x74,0x55,0xe4,0x25,0x3a,0xe5,0x65,0x9a,0x76,0x83,0xea,0xff,0x11,0xcb,0x4b,0xdb,0xbe,0xd6,0x64,0x56, +0xb7,0xae,0xf5,0xee,0xb7,0xb5,0xac,0x6c,0x29,0x61,0xca,0xa5,0x45,0x33,0x6e,0xe5,0xd4,0x38,0x49,0x87, +0x6a,0xec,0x58,0xb0,0x6a,0x81,0xfa,0x7a,0xd2,0x80,0x6e,0x23,0xac,0x5a,0xd5,0xc7,0xbb,0x95,0x96,0x69, +0xa3,0x05,0x28,0xa7,0xac,0x1b,0xef,0x79,0x81,0x14,0xb6,0x4e,0x5b,0xc5,0xd5,0xd0,0x68,0x79,0x68,0xa1, +0x26,0x23,0x06,0xdc,0x75,0x10,0x77,0xdc,0x69,0xa3,0xac,0x5b,0xe6,0xc8,0x06,0x69,0x57,0x8b,0x6c,0x69, +0xc4,0x30,0x33,0xa0,0x2d,0x55,0x54,0xb5,0x32,0x41,0x5b,0xe5,0xc3,0x55,0x11,0xaf,0x17,0x19,0x87,0xa4, +0x5f,0xc4,0x69,0xc7,0x32,0xea,0x35,0x53,0x32,0x86,0x25,0x60,0x57,0x64,0x2d,0x74,0xbd,0xeb,0xca,0xa6, +0x87,0x80,0x07,0x1c,0xbc,0x86,0x61,0xb9,0xa0,0x03,0x90,0x5b,0x81,0x6e,0xbc,0x07,0xcb,0x4d,0xca,0xb1, +0x05,0x44,0xc3,0xdb,0xab,0xdc,0xf6,0x9c,0xc4,0xc6,0xac,0xf9,0x1e,0x56,0x06,0xfd,0xf8,0xfa,0xd5,0x8b, +0xb2,0x5c,0xa9,0x03,0x4f,0xed,0xd1,0x25,0xb0,0x9c,0x99,0x79,0xfe,0xb9,0x0c,0xef,0x46,0xec,0x0e,0x7a, +0x78,0x74,0xf4,0x88,0x2e,0x3e,0xdf,0xfa,0xbf,0x97,0x61,0x47,0x29,0x2e,0x1c,0xa5,0x69,0xfa,0xe4,0x45, +0xd8,0xeb,0xfd,0x0e,0x6b,0xc1,0x1b,0xea,0xd8,0x13,0x62,0x84,0xa9,0x9a,0x49,0xb4,0x2c,0xa0,0x91,0xfc, +0xbd,0x84,0x4a,0x12,0x9f,0x86,0x94,0x0b,0xd2,0xe9,0x0a,0x9b,0xfd,0xbe,0x36,0xb5,0x95,0x4a,0x06,0x87, +0xa5,0xca,0x7c,0xb3,0x41,0xde,0x88,0x56,0x6e,0xf1,0x0c,0x4a,0xe4,0x5d,0xd4,0x80,0xe3,0x19,0xd8,0x8a, +0x01,0x89,0xfd,0x82,0x26,0xb6,0x54,0x91,0xa3,0x96,0x02,0x2a,0xd8,0x2d,0x55,0x80,0x32,0x66,0x25,0x4a, +0x39,0x00,0x71,0x47,0xfb,0x81,0x28,0x4e,0x68,0x3a,0x15,0xc5,0x4d,0x96,0x2f,0xb0,0x1f,0xd0,0xd7,0x22, +0x75,0x94,0x80,0x11,0x12,0xf0,0xa0,0x7a,0x58,0xc0,0xf3,0xc9,0x7a,0x40,0xb7,0xe3,0xd2,0x70,0x93,0x88, +0xb4,0xd8,0xe4,0x44,0xbb,0x9e,0xb9,0xd5,0x27,0x28,0xd3,0x6a,0xe1,0x66,0x93,0x4c,0x9d,0x1f,0x07,0x6a, +0x94,0x88,0x30,0x64,0x78,0x68,0xf8,0x1a,0x76,0x3e,0x0f,0x9d,0xfa,0xb0,0x3a,0x42,0xe9,0x70,0xb5,0x13, +0xaf,0x68,0x53,0x38,0x91,0xcf,0xa8,0xcf,0xe3,0xae,0x69,0xbd,0x67,0x4d,0x9f,0x94,0x25,0x2d,0x79,0x08, +0x35,0x37,0x62,0xe0,0xf1,0x05,0xd3,0x23,0x7c,0xc5,0x44,0x01,0x5f,0x31,0x21,0xc2,0x42,0x2f,0xd1,0xcb, +0xb3,0x6d,0x86,0xaf,0xc8,0x1d,0x8e,0x8b,0x50,0x68,0x4a,0x28,0x50,0xc2,0x2e,0x7e,0xda,0x42,0x43,0x29, +0x14,0x37,0x3d,0xc9,0x88,0xd7,0x55,0x29,0xbd,0x20,0x73,0xf5,0x73,0xbf,0xb0,0x44,0x61,0x78,0xf1,0x73, +0x39,0xd5,0x8f,0x66,0x30,0xd4,0xe9,0x48,0x26,0xb2,0x5b,0xc6,0x0a,0xe4,0x00,0xa6,0x22,0x2c,0x16,0x4e, +0x85,0xdf,0x78,0x1d,0x0a,0x55,0x2b,0x25,0x62,0x78,0xde,0x9d,0x27,0x69,0x94,0x7f,0x0c,0xaa,0xc7,0xdb, +0xe0,0x8e,0x85,0xbc,0xf5,0x84,0x5b,0x2a,0xb9,0x53,0x40,0xe2,0x0a,0x2e,0xa6,0xe9,0x49,0xc4,0xee,0xca, +0xad,0xfe,0x4c,0x5d,0xdd,0xda,0xca,0xa5,0xcb,0xf4,0xf1,0xa4,0xea,0xed,0x3c,0xe8,0xec,0x6f,0x6b,0xd0, +0x3e,0x67,0x88,0xe3,0x8a,0x34,0x64,0x84,0xd5,0x4e,0xb2,0x2e,0x05,0xc2,0x85,0x04,0x8e,0x40,0xf9,0x32, +0x5a,0x42,0xcd,0x15,0x42,0xc8,0x95,0x35,0x86,0xa1,0x64,0xa2,0x5b,0x70,0x2e,0x34,0x7d,0xb7,0x56,0xa8, +0x94,0x42,0xdf,0xad,0xb7,0x2d,0xb9,0x06,0x17,0xc3,0x21,0xc9,0xb6,0x86,0xe2,0xa9,0x80,0xea,0xed,0xf9, +0x17,0xdb,0x4b,0x80,0xbd,0x3d,0xf5,0xe9,0x34,0x14,0x6a,0x04,0x86,0x63,0x55,0x26,0x4a,0x96,0x67,0x34, +0x1b,0x92,0x46,0xa9,0x30,0x2a,0xfd,0x83,0xbf,0x57,0x53,0x51,0xec,0x78,0x1e,0xcf,0xaf,0x3b,0x9f,0xdf, +0x0e,0xaa,0x37,0x35,0x4d,0x86,0x2a,0xed,0xe0,0xec,0xdc,0x9d,0x04,0xc8,0x75,0x83,0x84,0x9e,0x3c,0x66, +0xf5,0x45,0x4d,0xe7,0xc0,0xda,0x03,0x95,0xcd,0x8e,0xb3,0x5f,0xe8,0xaa,0xaf,0xa1,0x0f,0xa4,0xfd,0x20, +0xee,0xee,0x2f,0x43,0x97,0xd5,0xce,0xe0,0x2a,0x92,0x22,0x93,0x6b,0xd2,0x77,0xcc,0xe0,0x52,0x8f,0xf9, +0xed,0x7e,0x15,0xc7,0x72,0x50,0x7c,0x56,0x7f,0x56,0x5b,0x72,0x67,0x21,0x10,0x7e,0xd5,0x25,0x37,0xca, +0x50,0x7a,0xdc,0xb9,0x1d,0x33,0x3d,0xcc,0xc4,0x86,0xa3,0xa2,0x1a,0x3d,0xa1,0xc3,0x99,0xb5,0xba,0x77, +0x4a,0x37,0x05,0xa7,0x58,0x7e,0x73,0x22,0xf7,0x7e,0x91,0xcf,0xe9,0x19,0x6d,0xd0,0x44,0x3d,0x51,0x16, +0x0e,0x16,0xca,0x9e,0x12,0x8d,0xd7,0xb7,0x2a,0x13,0x68,0x46,0x9b,0x2b,0x22,0x74,0x5e,0xe2,0x5a,0x5b, +0x8b,0x88,0xec,0x3f,0x1f,0x7d,0xce,0xa7,0x99,0x8a,0x95,0x46,0x8d,0x4d,0x63,0xe6,0xed,0x6a,0x1e,0xff, +0x25,0xa8,0xc0,0xfb,0x26,0xae,0xd2,0x80,0xfe,0x58,0xc2,0x58,0xe0,0x3b,0xe8,0x3c,0x43,0xef,0x6c,0xe2, +0x4e,0xc2,0xfd,0xcd,0x03,0x6f,0x73,0x36,0x51,0x76,0x1b,0xd6,0xac,0x04,0x33,0xb2,0x0a,0x9c,0xb9,0x12, +0x06,0x8b,0x5a,0x6a,0xa5,0x65,0xc3,0x6d,0x84,0xc3,0x1f,0x4b,0xb1,0x8f,0x13,0x69,0xb8,0x58,0x96,0xf6, +0x9d,0x9f,0x45,0xd2,0x50,0xa3,0x98,0x63,0x84,0x85,0xc4,0xf4,0xe8,0x9a,0x1d,0x28,0x85,0x75,0x57,0x2b, +0x6b,0xf0,0x3a,0xc0,0x77,0xcb,0x21,0x27,0xd2,0xc0,0x31,0xdf,0x69,0x3d,0x37,0x3a,0xdf,0x9b,0x38,0xf4, +0x97,0x18,0xe8,0xa6,0x21,0x7f,0xa9,0xa4,0x08,0x2c,0xf2,0x29,0xff,0xbb,0x22,0x9f,0xaa,0x4c,0x16,0xc9, +0x10,0x01,0x81,0x5f,0x71,0xef,0x82,0x62,0x49,0x5a,0xc1,0x80,0xf4,0x36,0xab,0xaf,0xb9,0xd8,0x44,0xb7, +0x41,0xf7,0x69,0xd3,0x5c,0xa3,0xfe,0x16,0x36,0xc7,0xb5,0x07,0x30,0xe5,0xa8,0x3f,0xf1,0x8b,0x09,0x9d, +0x25,0x10,0x88,0x17,0x33,0x23,0x0d,0xfa,0x4e,0xa4,0x41,0xfd,0xc4,0x24,0xd7,0x7d,0xc6,0x7d,0x65,0x09, +0x9d,0x74,0xdf,0x69,0x39,0x91,0x4a,0xce,0xc6,0x20,0x09,0x9f,0xef,0x66,0x3f,0x98,0xaa,0x05,0x26,0x5a, +0xc6,0x99,0xbd,0x79,0x6b,0x6b,0x33,0xcb,0x84,0x26,0xe9,0x3b,0x7b,0x37,0x51,0xb1,0x47,0x44,0xee,0x1e, +0xe6,0x13,0xeb,0xbb,0x22,0xea,0x8a,0xad,0x5f,0xef,0x9a,0x50,0x58,0x60,0xb8,0x2d,0x4c,0x93,0x19,0xc7, +0x4f,0xb3,0xb3,0x8e,0xaa,0x80,0xee,0x5b,0x3f,0xd7,0x02,0x6c,0x7b,0x26,0xea,0x6d,0x24,0x9b,0x88,0x0d, +0x7b,0xe5,0x42,0xed,0x52,0xfb,0x39,0xbf,0xcc,0x2f,0x25,0xd0,0x75,0xb3,0xf7,0xd3,0x46,0x67,0x62,0x42, +0xc3,0x92,0x36,0xf1,0x18,0x58,0xba,0x3e,0x38,0x19,0x0d,0x77,0xe6,0x46,0xcc,0x7c,0x45,0x61,0xa6,0xcd, +0x8d,0x3c,0xc3,0x8a,0x8b,0x99,0x9b,0x48,0x85,0x11,0x22,0x41,0xf3,0x79,0x2d,0x7c,0x17,0x08,0x8f,0x13, +0x08,0x51,0xf0,0x96,0x67,0x5c,0xc7,0x57,0x2e,0x66,0x27,0xd8,0x83,0x0a,0x64,0xc0,0x0a,0xbe,0x70,0x8c, +0xc9,0xf9,0xe4,0xf8,0x40,0x7e,0xec,0x1b,0xc7,0x3f,0x92,0x4d,0xd5,0x30,0x0a,0x8a,0xf0,0xde,0x8a,0x6d, +0x29,0x6b,0x81,0x39,0x93,0xa6,0x80,0xc2,0xf2,0x64,0xab,0x20,0xb2,0xd4,0xd4,0x9d,0xce,0xc6,0x9d,0xce, +0x7a,0x4a,0xa7,0x45,0x3b,0xf6,0xd8,0x78,0x91,0x9b,0x95,0x4f,0xa4,0x5f,0x67,0x87,0xc0,0xcb,0xe7,0x8f, +0x76,0x01,0x02,0xd7,0x34,0x25,0xed,0xe7,0x51,0x11,0x33,0xd4,0x1b,0xcb,0xd6,0xd3,0xca,0x36,0x4d,0xd9, +0x2f,0xb4,0x37,0xcb,0xdc,0xa3,0xa5,0x40,0x29,0x21,0x91,0xfa,0xda,0x44,0xa8,0xa1,0x49,0x07,0x0c,0x3d, +0xd8,0x52,0x4d,0xa6,0xcd,0x52,0x00,0x86,0xee,0xcd,0x02,0x37,0x09,0xcf,0x5d,0xda,0xbf,0xa8,0x8b,0x80, +0xed,0x8c,0xd0,0xe6,0x1a,0x93,0xfa,0x12,0xc0,0xd9,0xd5,0x9e,0x0e,0x43,0x97,0x38,0xa7,0x87,0xc8,0xcf, +0xe6,0xd3,0x8c,0x94,0x81,0x69,0xa8,0x9d,0xce,0xf7,0x00,0x38,0x00,0x27,0x89,0x48,0x73,0x96,0xbb,0xa6, +0x61,0x4b,0x0b,0x71,0x04,0xc8,0xc3,0xef,0xe1,0x45,0xc2,0x22,0x65,0xf0,0xe8,0x60,0xe9,0xe5,0x6e,0xe4, +0xe3,0xbe,0x65,0x00,0x56,0x57,0x3b,0x06,0x65,0x07,0xd0,0xa0,0x00,0x87,0x3b,0x6f,0xdf,0xbc,0x3f,0x6d, +0xc4,0x73,0xeb,0x92,0xba,0x24,0xb4,0xd1,0x35,0x04,0x2f,0x62,0x7c,0xc1,0xf2,0x9e,0x92,0xce,0x41,0x16, +0x0b,0xda,0x47,0x5f,0x56,0x2d,0x63,0xca,0x1e,0xa9,0xdd,0x7c,0xc2,0xc7,0xec,0x22,0xf9,0x80,0x33,0x56, +0xf1,0xeb,0xf6,0xfc,0x84,0x2d,0x92,0x04,0x9b,0xcf,0x85,0xb7,0xd6,0xab,0x9f,0x86,0xac,0x2e,0xd9,0x8a, +0x5a,0xfc,0x73,0x0d,0x7e,0x2a,0xdb,0x6c,0xa6,0x71,0x8d,0xe0,0x45,0xa0,0xc6,0x19,0x68,0x48,0x2d,0xe2, +0xa8,0x04,0x68,0x95,0x6e,0xc2,0xaf,0x34,0xba,0x7e,0x43,0x21,0x6c,0xab,0x96,0x6b,0x4a,0x67,0xbf,0x12, +0x61,0x76,0x40,0xa5,0x37,0x2d,0x75,0xeb,0x92,0x01,0x3e,0xf4,0xaa,0x20,0x3e,0x36,0x23,0xae,0xc0,0xa4, +0x16,0x3b,0xe4,0x62,0x97,0xb4,0xf1,0xb3,0x9f,0x98,0xa0,0x9d,0xd9,0xcc,0xa9,0x89,0x45,0x85,0x23,0x09, +0x36,0x69,0x5b,0xcd,0x87,0x73,0xa3,0x85,0x67,0x67,0x4b,0xd7,0x37,0x7c,0x79,0x7f,0x0c,0x44,0xd1,0x4f, +0x5b,0xe0,0xe7,0x3a,0x2a,0x86,0x23,0xfe,0x15,0x58,0x53,0x8c,0x4c,0xea,0x80,0xcc,0x4f,0xe6,0x38,0x09, +0xe7,0x15,0xbe,0xf9,0x50,0x27,0x0f,0x1d,0x1d,0x95,0x86,0xa3,0xad,0x5c,0xa8,0x7a,0xb8,0x0a,0x9e,0x50, +0x65,0xce,0xba,0x74,0x15,0x66,0x51,0x9e,0x2c,0x19,0x9f,0xdc,0x5f,0x86,0x6e,0x15,0x85,0x03,0x45,0x00, +0xb7,0x29,0xb9,0x65,0xdc,0x9c,0x70,0xee,0xb1,0x62,0x65,0x6d,0x1f,0xed,0x00,0xc3,0x85,0x1f,0x0d,0x4c, +0x35,0x72,0x2a,0x4e,0xd7,0xc3,0x65,0x90,0x77,0x0e,0x47,0x93,0x84,0x39,0xc3,0x92,0x7b,0x01,0x9c,0x23, +0x2a,0x74,0xf4,0x8c,0xa8,0x1b,0x38,0xf3,0x5a,0x8f,0xd6,0x78,0xd4,0x5e,0x68,0x6c,0x04,0x51,0x8a,0x48, +0x28,0x66,0x67,0x4e,0x0b,0x3d,0x11,0x7e,0xe3,0x0a,0xc7,0x92,0xc3,0xdf,0x50,0xe2,0x15,0x7e,0xe5,0x6e, +0x00,0x6c,0x81,0x55,0x3f,0xaa,0x92,0xa0,0x2a,0x9c,0x06,0x17,0xea,0x7e,0x50,0xf0,0x0f,0x0e,0x66,0x07, +0x56,0xd1,0x97,0xec,0xe7,0x38,0x81,0x3c,0x00,0x70,0xd7,0xaa,0xe0,0x95,0x17,0x5c,0x70,0x7f,0xad,0x14, +0x66,0xad,0x1d,0xe4,0xb5,0x39,0xc6,0xbc,0xe9,0xef,0x72,0x64,0xb7,0x02,0x04,0x62,0x82,0x76,0x89,0xe7, +0x64,0x5e,0x4b,0xb6,0x43,0x33,0x89,0xec,0xd8,0x65,0xe3,0x9a,0x83,0x7e,0xd3,0xaf,0x36,0x9b,0x64,0xbb, +0xe4,0x44,0x18,0xa9,0x6c,0x17,0x82,0x3c,0xc3,0xef,0xd5,0x03,0x6e,0x42,0x30,0xb8,0x50,0x37,0x6a,0x0f, +0x67,0xd4,0x73,0xcb,0x27,0xc6,0xbf,0x03,0x9e,0x24,0x8f,0x77,0x3f,0x19,0x72,0xd8,0x67,0xa9,0xf0,0x80, +0x4e,0x1f,0xce,0xfd,0x94,0x66,0x02,0xc7,0xc7,0xc9,0x55,0x57,0x73,0xaa,0x1f,0x1b,0xa9,0x5e,0x31,0x7c, +0x7d,0xc0,0xb9,0x8d,0x24,0xfd,0x68,0xab,0x1d,0x42,0xfd,0x55,0x47,0x08,0x1c,0x38,0x31,0x2a,0xc1,0xad, +0x86,0x78,0xf3,0x8d,0x1f,0x03,0x1d,0x71,0xf5,0xac,0xb4,0x77,0xbc,0x99,0xd3,0x6a,0x05,0xa4,0xf6,0x82, +0x9b,0xd0,0x79,0xb6,0xab,0x7b,0x02,0x57,0x87,0xf3,0xe6,0x8a,0xbf,0x15,0x99,0x23,0x7a,0xcd,0x7a,0x8a, +0xc8,0x39,0x6e,0x8c,0xf2,0x65,0xfb,0x86,0x4f,0x12,0x22,0xec,0xea,0xb7,0x9e,0xae,0x97,0x74,0x98,0x5e, +0x85,0xfc,0x81,0x60,0xf2,0x53,0x6f,0x09,0x28,0x3f,0x5b,0x8f,0xdb,0xfd,0xd6,0x91,0x18,0x9d,0x56,0xa5, +0xa6,0x4d,0x8e,0xf3,0x96,0xe9,0xcf,0x25,0x0c,0xaa,0x56,0x4a,0x1c,0x80,0x53,0xec,0xbc,0x26,0x67,0xb5, +0x06,0xa4,0x80,0x56,0x5a,0x8e,0x5c,0x20,0xde,0x1e,0x5b,0xdf,0x6e,0xf5,0x1f,0x34,0xe1,0xad,0x0b,0xcf, +0x6b,0xfd,0x36,0x8e,0x59,0x89,0xae,0xf7,0xb3,0xae,0xcd,0x4f,0x04,0xeb,0xb5,0x8f,0xf4,0xc6,0xbb,0xd9, +0xfc,0x2d,0xde,0x36,0xb0,0x0d,0x0d,0x40,0x75,0xe0,0x58,0xd3,0xcb,0xf1,0x0d,0x9e,0xb5,0x3c,0x57,0x93, +0x73,0x87,0xb3,0x43,0x2d,0x09,0xb6,0x77,0x05,0xd8,0x68,0xe3,0x12,0xe6,0x2d,0x04,0x22,0x2b,0xa7,0xca, +0x4d,0x72,0x6c,0xcb,0xf2,0x95,0xf3,0x52,0xec,0x4d,0x88,0x24,0x0f,0xbe,0x6c,0x46,0x49,0x84,0x7b,0xb1, +0xb5,0xa4,0xec,0x08,0x25,0x13,0x5a,0xcd,0xf0,0xbe,0x03,0x02,0x33,0xaf,0x06,0x17,0xcb,0x5b,0x37,0xca, +0x4d,0xe9,0xc6,0x6a,0x6e,0x90,0xf8,0xe9,0x24,0x09,0x32,0x7b,0x1d,0x7a,0xfc,0x6d,0x98,0x70,0x24,0x81, +0xbc,0x23,0x0e,0x5f,0x03,0xd4,0x12,0x27,0x33,0x9f,0x09,0x9f,0x88,0x4b,0xc2,0xf1,0x31,0x6a,0xf1,0xa9, +0xec,0xf4,0x69,0x2d,0x46,0x89,0x0a,0x8a,0x54,0xd2,0xc1,0xa4,0x98,0x24,0x36,0x62,0x06,0x6b,0x51,0x1d, +0x1b,0x94,0x29,0x07,0xaf,0x08,0xd2,0xad,0x67,0x0f,0xad,0x0a,0x5c,0x64,0xc2,0xa6,0xf0,0x84,0x0f,0x54, +0xf0,0x94,0xae,0xc8,0xe2,0xfc,0x95,0x09,0x76,0xc1,0x04,0xbe,0xd3,0x8f,0xb5,0xc8,0x26,0x80,0x49,0x43, +0xe0,0x64,0xeb,0x92,0x1f,0x6f,0x1b,0x60,0x84,0x32,0xe0,0xb9,0x35,0xe0,0x95,0x3c,0x39,0x6c,0x76,0x1e, +0x68,0x75,0x0b,0xab,0xd3,0x50,0xf8,0x09,0xc7,0x3b,0x63,0xcc,0x38,0x01,0x54,0xce,0xf8,0x77,0xa2,0x16, +0x16,0x15,0x2f,0xeb,0xb7,0x22,0x44,0x5b,0x73,0x09,0xdb,0xfb,0x7d,0x73,0x89,0x88,0x50,0x4c,0x10,0x0b, +0x85,0x44,0x5a,0x44,0x7b,0xd8,0xd4,0xb4,0x79,0x16,0x54,0xfb,0x77,0x73,0x23,0x9f,0x3a,0xb2,0xf1,0x72, +0xb2,0x2f,0x6b,0x41,0x20,0x11,0xdd,0xa6,0xbd,0xf1,0x33,0xb8,0xfa,0x35,0xd1,0xad,0x25,0xb3,0x50,0xcc, +0xbb,0xd2,0x2c,0xc4,0xf7,0x7e,0x56,0xbb,0xd3,0x09,0x64,0xf1,0xea,0x04,0xf5,0xbb,0xaa,0x70,0xe3,0xf7, +0xcf,0xf3,0x5d,0x6d,0x05,0x68,0x7e,0xe1,0x55,0x08,0xf6,0xdc,0x1d,0x80,0x46,0x01,0xca,0x17,0x4d,0x71, +0x6d,0x7a,0xca,0x08,0x90,0x4d,0xd7,0x2a,0x38,0x55,0xee,0x44,0x66,0x53,0x64,0x61,0xac,0xbc,0xef,0xe8, +0x15,0xf4,0x4b,0xad,0x4f,0x1a,0x1f,0x5c,0x5c,0x98,0x2f,0xbc,0xad,0xaf,0xbd,0x50,0x3f,0x01,0x48,0x2d, +0xd4,0xa7,0x02,0x96,0x06,0x10,0x61,0xe7,0x57,0xe6,0x1b,0xe0,0x59,0xb4,0x40,0x31,0xac,0xe2,0x9d,0x87, +0x0f,0x1d,0xa5,0xd0,0xc3,0x03,0xca,0x1a,0xc6,0x56,0x0f,0x1d,0x3f,0xd5,0x8b,0xf8,0x2a,0x5b,0x2e,0xde, +0x41,0xde,0x5b,0x23,0x6a,0x63,0xc1,0xa1,0xa3,0xc7,0x3f,0x44,0x49,0xd9,0xef,0x07,0xfa,0x96,0x61,0xa5, +0x85,0xe6,0x62,0xd7,0x82,0xb0,0xe6,0x68,0x60,0x18,0x5b,0x68,0xde,0x43,0xcb,0x02,0xfa,0xb2,0xc2,0xe1, +0x0a,0x13,0xbf,0x0a,0xbe,0x6e,0x58,0x1f,0x41,0x5c,0xdc,0xdf,0x97,0xdf,0x61,0x74,0xbd,0xd0,0xd7,0xae, +0x23,0x16,0x94,0xc0,0x7c,0xee,0x88,0x6e,0x73,0x19,0x2b,0xe2,0xe6,0x7b,0x78,0x47,0xfd,0xf2,0x0f,0x24, +0xf5,0xbf,0xc1,0xf5,0x03,0x6b,0x0d,0xa4,0xd9,0x49,0x96,0x5e,0x10,0x7b,0x56,0x0f,0x1b,0x69,0x58,0xfa, +0x07,0x7c,0xa2,0x30,0x89,0xfc,0x20,0xfc,0xa6,0x14,0xf4,0x69,0x95,0x5b,0xf5,0x4a,0xdd,0x7f,0x5f,0xa2, +0xe7,0xb6,0x00,0x63,0xa9,0x1e,0xe2,0xc3,0x4b,0x86,0x64,0xdd,0x7a,0xc7,0x07,0x4a,0x6a,0xa9,0xa5,0x97, +0xc6,0x76,0x1a,0xd1,0x03,0x5e,0x13,0x87,0x42,0x7b,0x2d,0x91,0x58,0x77,0xd7,0xea,0x92,0x78,0xdc,0xd0, +0x79,0x47,0x1c,0x6c,0x19,0xef,0xad,0x57,0xc4,0xbf,0xc5,0x7b,0x8c,0xd9,0x0a,0x83,0x4e,0x93,0xe6,0x88, +0xd2,0xbc,0x39,0x7d,0xba,0x3b,0xc1,0x23,0x4a,0xc0,0xdc,0xd0,0x1e,0x3a,0x9d,0x76,0xb2,0x3d,0x70,0x82, +0x3d,0x2b,0xc5,0xe7,0x94,0xe2,0xf4,0x2a,0xde,0x83,0x73,0xc4,0xde,0x22,0x8b,0x45,0x30,0xb4,0xa4,0xfd, +0x79,0x6f,0x99,0xfc,0x1a,0xef,0x45,0x7b,0xe2,0x70,0x45,0xfb,0xde,0x45,0x72,0xa9,0xd1,0xe4,0x21,0x93, +0x59,0xaf,0xf6,0x28,0xdf,0xa4,0xa0,0x57,0x79,0xbe,0x5e,0xd5,0x0b,0x7e,0x4c,0xd9,0x9e,0xb0,0x2e,0xa1, +0xd8,0x2b,0xa2,0x0f,0xf1,0x62,0xb8,0xf7,0xcf,0x6c,0xbd,0x57,0x5c,0x65,0xeb,0xe5,0x62,0x2f,0x8f,0x69, +0xb3,0x2b,0xf7,0x3e,0x66,0xeb,0x7c,0xef,0x3c,0x8b,0xf2,0x05,0x15,0x7a,0x63,0x7d,0xfd,0x17,0xfa,0xfa, +0xad,0xd2,0x9f,0x15,0x54,0x2b,0xae,0x13,0x9b,0xff,0xd9,0x55,0xff,0x6b,0xb3,0x0c,0xeb,0xdd,0x97,0xf4, +0xee,0xdb,0x4c,0xb9,0x75,0x52,0x16,0xc4,0x1c,0xce,0xeb,0x35,0x3c,0x84,0x84,0xeb,0x3d,0xdd,0xa1,0x3d, +0xc4,0xd3,0x25,0x79,0xbc,0xf0,0xf7,0x88,0x8d,0x8c,0x60,0x48,0x12,0xb3,0xb0,0x18,0x07,0xe0,0x70,0x38, +0x74,0xb6,0x66,0xb4,0x8a,0x38,0x2d,0xb2,0x9c,0x7d,0xd5,0x8c,0xb6,0x7a,0xea,0x3c,0x7b,0x41,0x3c,0xb7, +0xf3,0x8c,0xc8,0xfc,0x08,0x9c,0xe6,0xd7,0xd7,0x94,0xf2,0x69,0x1a,0x2d,0xb3,0x4b,0x73,0xf7,0xec,0xe4, +0xf0,0xe8,0xb0,0xba,0x7b,0x7f,0xf8,0xe3,0xe1,0x63,0xba,0x7d,0xf1,0xea,0x87,0xbf,0x8e,0x0e,0x8f,0xe8, +0xea,0xfb,0x2f,0x8f,0xbe,0x38,0x7c,0x8e,0x14,0x27,0x2f,0x0e,0x1f,0x7f,0x31,0xa2,0x2b,0x93,0xc5,0xb3, +0xe4,0x32,0x29,0xa3,0x25,0x5e,0x8a,0x43,0xb7,0xef,0xbc,0x7d,0xfd,0xfe,0xc7,0xd1,0xe8,0x11,0x5d,0x7d, +0xf5,0xfa,0xc7,0xa3,0xbf,0x22,0xf9,0xeb,0x17,0xff,0x3a,0xfc,0x92,0x7e,0xdf,0xbf,0xfc,0xcb,0x88,0xcb, +0x7a,0xff,0xe2,0xf4,0xd1,0x8f,0x7b,0x2f,0x8f,0x4e,0x90,0xea,0xc5,0xe1,0x5f,0x1e,0x23,0xd5,0xdb,0x7f, +0x7d,0xfd,0x7a,0x34,0xfa,0x1c,0x15,0x7e,0xfa,0xfa,0xe8,0xd1,0xd1,0x48,0x25,0xf8,0xe6,0xbb,0xef,0x9f, +0xbe,0x3f,0x3c,0x7a,0xff,0x8c,0xae,0x4f,0x5f,0xbf,0x7d,0xf4,0x23,0x6a,0x77,0x32,0x78,0xff,0x6e,0xf4, +0x39,0xb2,0xa2,0x76,0xc7,0x4f,0x13,0x70,0xd5,0xdf,0xd0,0x09,0x4a,0x14,0x66,0x32,0x07,0x70,0xba,0xba, +0x3b,0x79,0xfb,0xda,0x31,0xac,0xc3,0xe1,0x31,0x23,0xac,0x1f,0x9b,0xc0,0x46,0x74,0x98,0xc4,0x83,0xc3, +0x99,0x98,0xef,0x9a,0xae,0xbc,0x8e,0x2e,0x69,0xea,0xaf,0xe5,0xb0,0xb0,0x7b,0xf3,0x34,0xbe,0x5e,0x21, +0x82,0xe1,0x1a,0x01,0x6f,0x9d,0x17,0xeb,0xeb,0x64,0xc1,0x00,0xfc,0xce,0x5b,0x38,0xe1,0xca,0xd3,0x93, +0x75,0x0e,0x62,0x0e,0xfd,0x96,0x2d,0x4b,0x1a,0x26,0x34,0x87,0x0d,0x1b,0xf7,0xde,0xc2,0x64,0x14,0xb7, +0x2b,0xd1,0xe8,0x9b,0x07,0xb4,0xa7,0xd5,0x53,0xf0,0xef,0xde,0xf3,0x08,0x11,0x8e,0xd0,0xb7,0x74,0xdc, +0x5d,0x7e,0x34,0x17,0x7b,0x44,0x9a,0x50,0xd6,0xde,0x27,0x07,0xe2,0x70,0xc8,0xfd,0xfa,0xfa,0x68,0xf8, +0x58,0xee,0x71,0x7b,0xf2,0x06,0x83,0xfa,0x6a,0x0d,0xa0,0xbc,0xef,0xbe,0xe7,0x4f,0x69,0x79,0xb2,0x3d, +0x1e,0x75,0xeb,0x8b,0x37,0x78,0x09,0x07,0x9e,0xbd,0x67,0x19,0xcd,0xb7,0x77,0x11,0x0b,0x2f,0x9a,0x4f, +0xfe,0xe3,0x2e,0xe5,0x35,0x6f,0xf7,0xe9,0x9b,0xbf,0x53,0xf6,0x6f,0xd6,0xe5,0x1e,0x6d,0xac,0xef,0xb0, +0x26,0xe8,0xf6,0x87,0x28,0xbf,0xc6,0x96,0xf0,0x1d,0x88,0x35,0xa5,0xcf,0xc3,0xe3,0x3c,0xa3,0x87,0x2f, +0x9f,0xf1,0x8c,0x2e,0xa3,0x3d,0x2d,0x4d,0xa1,0x69,0x62,0xae,0xbf,0x79,0xfb,0xf2,0x8d,0xb9,0x39,0xa1, +0x0d,0xe2,0x5c,0x6d,0x0c,0xa2,0x31,0x31,0xf5,0x1e,0xa9,0x7a,0xdb,0xd5,0x9e,0x05,0x6a,0x4b,0x02,0xdd, +0x64,0xaa,0xfe,0x6b,0x1c,0xaf,0x50,0x07,0x61,0xc9,0x1e,0xb8,0x4e,0xb1,0x8a,0xd2,0x29,0x74,0xe9,0xe1, +0x67,0xd1,0x65,0xf6,0xd9,0xcc,0xf1,0x44,0x3a,0x45,0x37,0x9e,0x4f,0x7f,0xfa,0x7d,0x9f,0x71,0x2a,0xb3, +0x9b,0x4a,0x76,0x7b,0xb3,0xf7,0x0c,0xfe,0xc4,0x87,0xf1,0xa3,0x87,0x78,0x8e,0xf0,0x01,0xc4,0xbf,0xbc, +0x7c,0xff,0x46,0x39,0xa8,0x7a,0xc3,0x62,0x7d,0x2e,0x82,0x54,0x77,0xe4,0x1f,0x7e,0x59,0x99,0x31,0x3b, +0xa7,0x0a,0x5c,0xed,0x81,0x42,0x4f,0x56,0x45,0x53,0x36,0x5c,0x34,0xd4,0x68,0xb4,0xc7,0xd7,0xeb,0xa5, +0x5f,0x72,0xbd,0xe0,0x8a,0x9a,0xdd,0xf4,0xfb,0xdb,0xaa,0x4d,0xbf,0xc7,0x79,0xf6,0x36,0x5a,0x34,0xb0, +0x6e,0x10,0x56,0x56,0x22,0x2a,0x97,0x12,0x50,0xb9,0x1f,0x3a,0x23,0x47,0xf5,0x98,0x9b,0xf6,0x89,0x9c, +0x15,0xa9,0xe1,0x80,0x88,0x04,0x93,0x17,0xf6,0x23,0xf4,0xcf,0xbf,0xb2,0x94,0xcf,0x09,0x15,0xdf,0x7a, +0xf0,0x97,0xa3,0x91,0x3f,0xf8,0xe2,0x0b,0xfc,0x19,0xd1,0x9f,0xc7,0x7f,0xc1,0x9f,0xcf,0xe9,0xcf,0xe7, +0x7f,0xc5,0x1f,0xbc,0x7d,0x84,0xb7,0x8f,0xf0,0xf6,0x08,0x2f,0x8e,0x0e,0xe9,0xcf,0x21,0xde,0x1e,0xf2, +0xb7,0x23,0x7f,0xe4,0x7f,0x01,0x0b,0x0d,0xfa,0x47,0x4f,0xf1,0x1a,0xe9,0x8e,0x28,0x27,0x7c,0xf4,0xe8, +0x11,0xfd,0xfb,0xfc,0xb1,0x8f,0x5c,0x1e,0x7d,0x39,0xf2,0x91,0x25,0xf2,0x7e,0x4c,0xe9,0x1e,0x1f,0x3d, +0xf6,0x51,0x18,0x4a,0x45,0xf1,0x5f,0x50,0x5a,0xd4,0x05,0x95,0xfa,0xcb,0x17,0x8f,0xfd,0xbf,0x50,0xba, +0xbf,0x7e,0x3e,0x9a,0x99,0xe8,0x30,0xca,0x92,0x5d,0x63,0xf5,0xc2,0x94,0x3d,0x0a,0xd3,0x27,0xe1,0x68, +0x92,0x06,0x83,0x14,0xc1,0xdf,0xbe,0x79,0x7d,0xea,0xf4,0x5d,0x7e,0xe4,0xf4,0x89,0xc4,0x1d,0x38,0x5e, +0x5f,0xf7,0xa3,0x41,0xf9,0x8c,0x0e,0x50,0x61,0xe2,0x3f,0x8f,0x3c,0xa4,0x31,0x09,0xa2,0x3f,0xd3,0xf3, +0x23,0x1e,0x44,0xf1,0xdf,0xd5,0x03,0x55,0xae,0x84,0x8d,0xe1,0xe1,0x52,0x12,0x4d,0x4a,0x74,0x2c,0xe0, +0x40,0x4f,0x8e,0x0f,0xd4,0x05,0xde,0x32,0x3e,0xa0,0x80,0xe2,0x10,0x4d,0x24,0x10,0x4f,0x19,0xb4,0xed, +0x66,0x2c,0xf8,0x44,0xa4,0x89,0xf6,0x3c,0xcb,0xaf,0xab,0x45,0x06,0x3f,0xc2,0x70,0xf8,0x70,0xfa,0x74, +0xf0,0xaf,0xb3,0xc5,0xcc,0x93,0x9b,0x68,0xf0,0xfb,0xcc,0x9b,0x9e,0xdd,0xfc,0xbb,0xf7,0xbf,0xff,0xf4, +0xe0,0xcf,0x3f,0xed,0x3f,0x3c,0x73,0xcf,0xbc,0xe3,0x27,0xfe,0xf0,0x6c,0x32,0x0e,0xee,0xb6,0xf0,0x58, +0x3e,0x3b,0xdb,0xcc,0xee,0x1e,0xfb,0xdb,0x07,0x07,0x7e,0x1a,0x36,0xa6,0x5f,0xb4,0xa0,0x15,0x8a,0x93, +0x90,0x2a,0xee,0xc7,0x9e,0x58,0x88,0xb9,0xda,0xcb,0x13,0xbc,0x91,0x25,0x11,0xee,0x19,0xae,0x48,0x33, +0x4c,0xd1,0x32,0x86,0xfe,0x15,0xe7,0xbb,0x36,0x47,0xc1,0xa1,0xbb,0x77,0x05,0xc8,0x03,0x46,0x05,0x88, +0x17,0x38,0xc1,0x71,0xbc,0x72,0xa3,0xfc,0xbd,0x84,0x0e,0xda,0x75,0x51,0x4a,0x92,0x88,0x28,0x01,0x3a, +0x0f,0xcb,0xbd,0xc7,0xec,0x00,0x48,0x1b,0x25,0xa4,0x98,0x7b,0x87,0x34,0x1b,0x69,0xe7,0x9c,0xe3,0xa4, +0x8c,0xd2,0x05,0xdd,0xaf,0x61,0x1b,0xce,0xf7,0xb4,0xae,0xc5,0x08,0xa3,0xe7,0x78,0x7e,0xef,0x50,0x62, +0x7a,0x7f,0xaa,0x59,0x30,0x4f,0xae,0xb5,0xaa,0x07,0x94,0xaa,0x7a,0x23,0x2a,0x7a,0x80,0x76,0xf5,0xbd, +0x45,0x72,0x71,0x11,0x63,0x77,0xb7,0x8a,0xc9,0x1a,0xc1,0xc2,0x27,0xbd,0x81,0x87,0xd1,0xa0,0x31,0x18, +0x0d,0xbe,0x1c,0xcc,0xee,0x68,0x02,0x1f,0x6e,0xab,0x27,0xb3,0x07,0xac,0xc4,0x68,0xd4,0x0d,0xf6,0xfc, +0xb8,0x52,0x55,0xb3,0xfd,0x69,0x7b,0xbd,0x4c,0x7a,0x38,0x67,0x94,0x18,0xa9,0xd7,0x0b,0x95,0x7e,0x6f, +0x1e,0xa5,0xe8,0xc7,0x73,0xea,0x59,0x04,0x76,0xe1,0x9e,0xb9,0x8e,0x3e,0xee,0x65,0xe9,0xf2,0x23,0x63, +0x46,0x44,0x10,0x0a,0xd2,0x50,0x3c,0x7d,0x7f,0xf2,0xf2,0xe5,0x9e,0x44,0x1e,0x2e,0xf6,0xdc,0xcf,0x9e, +0x7e,0xb6,0x07,0x73,0x87,0xf5,0xe5,0xd5,0xde,0x67,0xff,0xfa,0x8c,0xbf,0xfb,0x2c,0xb2,0x9e,0xfd,0xfe, +0x99,0xe7,0xf3,0x87,0x0b,0x9c,0x3e,0xc5,0xde,0x67,0x23,0xeb,0xe5,0x97,0x9f,0xf9,0xfc,0x05,0xde,0x5f, +0x7d,0x5c,0x5d,0xc5,0x29,0xe5,0x38,0xf8,0xcc,0xeb,0xed,0xd1,0xa8,0x7f,0x44,0xa5,0xf6,0xd2,0x38,0xa1, +0xb7,0xb9,0x90,0x87,0x18,0x20,0x9a,0xfd,0x7b,0x30,0xaf,0xa2,0x0f,0xff,0xdf,0xea,0xbe,0x85,0xbd,0x6d, +0x1b,0x59,0xf4,0xaf,0xd8,0x6c,0xea,0x88,0x16,0x25,0x4b,0x6e,0x92,0xee,0x4a,0xa1,0x75,0x1c,0xe7,0x79, +0xb6,0x79,0xd4,0x76,0x37,0x77,0xaf,0xe3,0xeb,0x43,0x59,0xb4,0xc4,0x46,0x26,0xb5,0x24,0x65,0x27,0x75, +0x7c,0x7f,0xfb,0x9d,0x07,0x00,0x02,0x20,0x28,0x3f,0xda,0xed,0xdd,0xed,0xf7,0xa5,0x16,0x81,0x01,0x30, +0x18,0xbc,0x06,0x83,0x79,0x88,0x32,0x5d,0xa2,0xa2,0xb6,0xdd,0x4c,0xe3,0x92,0x3c,0x6e,0x57,0xe2,0xec, +0xca,0xe7,0x15,0x70,0xbf,0x0f,0xf0,0xd2,0xcd,0x2b,0x45,0x78,0x69,0xa2,0x14,0x7a,0x8f,0xf7,0x84,0xed, +0x32,0x24,0xf6,0x07,0xbd,0x81,0xf0,0x99,0xb5,0xee,0x28,0xf4,0xed,0x9b,0xb3,0xd4,0x03,0xe5,0xf0,0xca, +0x3a,0xde,0xe0,0x32,0x2e,0x90,0xaa,0x24,0xe0,0x11,0x1c,0x6e,0xc0,0xc3,0x4d,0x50,0xb7,0x96,0x5d,0x7a, +0x4e,0x2f,0xc9,0x21,0x6d,0xf1,0x19,0xe3,0xc2,0xe3,0xd1,0x36,0x49,0x31,0xb9,0x38,0x9d,0xbd,0x48,0xd9, +0x14,0x9b,0x3e,0x0e,0x80,0x02,0xa8,0xda,0x8e,0xbf,0x77,0xf9,0xea,0x41,0xbf,0x59,0x0d,0x1d,0x7f,0xbd, +0x06,0xf6,0x94,0x7f,0xbd,0x4d,0x52,0x0a,0x2b,0x8d,0xbf,0x3f,0x3e,0x17,0xb5,0xfd,0x72,0xb8,0x47,0x4e, +0x70,0xe7,0xd1,0xd7,0x67,0xc0,0xcd,0xca,0xdf,0x1f,0x96,0xf3,0x22,0x96,0x1f,0xb8,0x63,0x23,0x36,0xff, +0x2c,0xcb,0x57,0xe4,0x37,0x4d,0xfb,0xfd,0x26,0xbd,0x90,0x60,0xef,0x53,0xe0,0x0e,0x4e,0x11,0xd5,0xd3, +0xdf,0xf6,0x31,0xe1,0xcd,0xe4,0x0b,0x7f,0xbd,0x95,0x27,0x3a,0x7c,0x96,0xc5,0xe2,0x33,0xe5,0x8a,0xdf, +0x7a,0x1e,0x74,0xeb,0x6d,0x46,0xbf,0xd4,0xda,0x82,0x53,0x98,0xb7,0xdb,0x91,0xed,0x18,0x00,0xbd,0x2e, +0xe1,0x45,0x85,0xec,0x89,0xc8,0x94,0xc8,0x27,0x8b,0x22,0x7e,0x62,0x45,0x17,0x7a,0x91,0xee,0xc0,0x11, +0xb6,0x62,0x06,0x4d,0x8f,0x85,0xab,0x67,0x63,0x9e,0x20,0x93,0x50,0xed,0x82,0x57,0x2a,0xc2,0x90,0x5c, +0x57,0xc2,0x33,0x1e,0xad,0x26,0x97,0x0a,0x69,0x0c,0x13,0x43,0x38,0xcf,0xa5,0xb9,0x81,0x8b,0x89,0xe2, +0x28,0xa8,0x39,0xc8,0x81,0x54,0x84,0x43,0xe9,0x74,0x63,0x43,0xcd,0x03,0xba,0x17,0xe3,0xcd,0x5d,0x4b, +0xd1,0xc7,0x76,0xfb,0xf1,0x63,0x5f,0xda,0x6a,0xa0,0x4b,0x11,0xd8,0x2b,0x51,0x39,0x4f,0xa5,0xe4,0x67, +0x63,0x54,0x20,0x08,0xca,0xaa,0x43,0x39,0xaa,0x4a,0x48,0x87,0x16,0xba,0x50,0xcf,0x1b,0x6a,0xa1,0x8f, +0x23,0xe9,0xfc,0x0b,0x0f,0xef,0x68,0x7c,0x0a,0xf7,0xd2,0xe9,0x2c,0xf9,0xf5,0xf3,0xfc,0x3c,0xcd,0x16, +0xff,0x84,0x3d,0x7a,0x79,0x71,0xf9,0xe5,0xeb,0x6f,0xe4,0x7b,0x4b,0x15,0xda,0xd5,0x0b,0xed,0x3e,0xdb, +0x7b,0xfe,0xe2,0xe5,0xab,0xd7,0x6f,0xfe,0xfb,0x6f,0x3f,0xbd,0x7d,0xf7,0xfe,0xc3,0xcf,0xfb,0x07,0x87, +0xbf,0xfc,0xfd,0xe3,0xff,0xfa,0xc7,0xff,0x36,0x0b,0x7d,0xa7,0x17,0x82,0x9b,0x02,0x1c,0xc5,0x4f,0x7e, +0xfc,0xcb,0x5f,0x4d,0xa0,0xff,0xaa,0xd7,0x6c,0x02,0xac,0xeb,0x00,0xff,0xf7,0x7f,0xe4,0x61,0xd4,0xf2, +0x4f,0xda,0x1d,0x18,0xb2,0xa3,0xe3,0xc1,0x27,0x6f,0xf8,0xf0,0xe9,0xce,0x28,0xe8,0x6e,0x7d,0xfb,0xf4, +0xc9,0xab,0xe2,0xb9,0x45,0xc8,0xae,0x64,0x61,0x3c,0xcc,0x76,0x7a,0xc3,0x4e,0x27,0xf3,0xa3,0x76,0x98, +0x1e,0x91,0x14,0x87,0x42,0x3f,0xb7,0xf8,0x27,0x51,0xad,0xe5,0x6f,0xaa,0x03,0xa9,0xd3,0xf7,0xfd,0xca, +0x49,0xa7,0x3e,0x61,0x52,0xe4,0xed,0xe3,0xdd,0x0f,0x6f,0xfe,0x16,0x7f,0x55,0x53,0xc0,0x20,0x7b,0xff, +0x49,0xe0,0xfd,0xd7,0x77,0x95,0x58,0xcb,0x3e,0x3d,0x16,0x09,0x14,0x55,0x6c,0x59,0x8c,0x5b,0x97,0x31, +0x23,0xff,0xbb,0x10,0x6a,0x3d,0x95,0xba,0x6a,0x25,0x78,0x40,0x7d,0x5a,0xa5,0xa7,0x5a,0xf9,0x23,0xd5, +0x6f,0x78,0x93,0x5d,0x4d,0x80,0x73,0x19,0x8f,0x8b,0xec,0xf4,0x33,0x2b,0xb0,0x51,0x35,0xcc,0x40,0x26, +0x67,0x5f,0xd9,0x96,0x9f,0x62,0xb9,0xc9,0x07,0x56,0xdf,0xac,0x68,0x8f,0x6e,0xcd,0x88,0xcb,0xca,0x6a, +0xf8,0x72,0x3d,0x88,0x8d,0xf2,0xe4,0x9e,0xe4,0x7d,0x0e,0x7b,0x3e,0xdc,0x3e,0x90,0xe5,0xb3,0x17,0x54, +0x7d,0x39,0x99,0x0b,0x29,0x13,0x65,0xbd,0xe0,0x81,0xe1,0xbc,0x14,0xd5,0x96,0x96,0xe7,0xfb,0x74,0x07, +0x0f,0xe9,0x17,0xb4,0x9f,0x42,0x8d,0xfc,0x41,0x6f,0xe1,0xbd,0x0a,0x8f,0x49,0xc6,0x69,0xd8,0x0b,0xb7, +0xe2,0xdf,0x25,0x09,0x13,0xab,0xb7,0x7e,0xbe,0x3d,0x63,0xf8,0x19,0xc5,0xb1,0xc5,0xc8,0xae,0x69,0x9d, +0xa3,0xdd,0xfe,0x65,0x92,0x9f,0x5f,0xc2,0x69,0xae,0xaf,0x33,0x3c,0xc2,0x5f,0xc2,0x42,0xdd,0x27,0x3d, +0xc7,0x61,0x2a,0x14,0x1c,0x31,0xea,0xab,0x2e,0x8d,0xaa,0x40,0xba,0xcf,0xdf,0xbf,0x7b,0xc1,0x2a,0x5a, +0xe4,0x42,0xc8,0x50,0x55,0x2c,0x5b,0xdb,0x3f,0xfc,0x60,0x66,0xa2,0x67,0xae,0x2e,0x72,0x33,0x68,0x95, +0xb9,0x5b,0xb6,0x10,0x2d,0xc1,0xa5,0x54,0xcf,0xf5,0x14,0x94,0x07,0x2b,0xda,0x2d,0x9e,0x91,0xa6,0xa6, +0x98,0x99,0x91,0xaf,0xd3,0xe5,0x97,0xc5,0x14,0x0e,0xb7,0x58,0xdb,0xc7,0x8c,0x79,0xba,0xe4,0x6c,0x9c, +0xa8,0x68,0x3a,0x80,0xdb,0x8f,0xf6,0xc2,0xe6,0x8c,0x29,0x32,0x92,0x5c,0xc5,0x4b,0x64,0xf4,0x2a,0x5e, +0xad,0xcc,0xa4,0x6b,0xaa,0x88,0x25,0x35,0x67,0x79,0x76,0xce,0xf2,0x13,0x34,0xfa,0x41,0x99,0xad,0x38, +0xc2,0x51,0x0b,0x2e,0xf9,0x2d,0xde,0x39,0xcb,0xe3,0xf8,0x04,0x7f,0xa9,0x2a,0xdf,0xa0,0xd3,0x1b,0xe4, +0xef,0xca,0x2c,0x5b,0x9b,0x23,0x39,0xb0,0xda,0xb3,0x84,0x0e,0x09,0x64,0x1f,0xa2,0x8b,0x28,0x99,0xe3, +0x09,0xb9,0x46,0xde,0x01,0xd1,0xf4,0x74,0xed,0xfd,0xe1,0x6e,0x77,0x0d,0x66,0x31,0x9c,0xb0,0xc0,0x41, +0x4c,0x32,0xbc,0x2f,0x46,0x6b,0xe5,0x65,0xd6,0xc1,0x50,0x97,0x42,0xf0,0x24,0x9b,0x6e,0xd9,0xa3,0xaa, +0x0b,0xd6,0xc8,0xd5,0x90,0xf1,0x80,0xa9,0x71,0xa7,0xa6,0xf4,0xa9,0x88,0xe3,0x73,0xc4,0x6d,0x5c,0x89, +0x9f,0xce,0x44,0xa5,0x6b,0xe4,0xba,0x07,0x1a,0x1c,0x6a,0xd3,0x05,0xd8,0x70,0x3c,0x84,0x86,0xa9,0x64, +0xed,0x3d,0x41,0x7a,0x38,0x73,0x30,0x4e,0x29,0x7a,0x59,0x09,0x1e,0x68,0xea,0x12,0xf0,0xaf,0xe8,0x0a, +0x18,0xdd,0xb3,0x06,0xa9,0x59,0x48,0xe3,0x18,0x61,0xaa,0xd2,0x37,0x7c,0x65,0xc0,0xa7,0xe1,0x52,0xa3, +0xaf,0x6c,0x68,0x4c,0xb1,0x2f,0x4c,0x85,0xef,0x44,0x03,0x1d,0x28,0x30,0x45,0xc9,0x05,0xde,0x14,0x13, +0x9c,0x2e,0x01,0x5e,0xc7,0xe9,0xf5,0x56,0x1b,0x6e,0xad,0x7b,0x40,0x56,0x9a,0xf3,0xc0,0x8e,0xb3,0x74, +0x8c,0xe5,0x65,0xf8,0x94,0x0c,0x5c,0x1d,0xf0,0xeb,0x28,0x97,0x02,0x0e,0x6e,0x3e,0x47,0x12,0x01,0xfa, +0x50,0xfb,0x0c,0x39,0xf9,0x14,0x18,0xf5,0x02,0x57,0xf3,0xa4,0x20,0x57,0x94,0x72,0xe5,0x3e,0x8e,0x7f, +0xc0,0x43,0x5d,0xd1,0x1b,0x1a,0x42,0x15,0xb0,0x48,0xdc,0xd7,0xd7,0x60,0xa3,0xc4,0x81,0x05,0x92,0x73, +0xcb,0x34,0x1d,0x90,0xb4,0x84,0x8e,0x92,0x8a,0x01,0xd8,0x5a,0x34,0x45,0x36,0xb6,0x45,0x9e,0xa1,0xfd, +0x2e,0x1a,0x48,0x7d,0x99,0x19,0x21,0x96,0x1b,0x7a,0xce,0xa1,0x13,0x87,0x62,0xa1,0xb8,0xf4,0xff,0x95, +0xe4,0x95,0x71,0x40,0x69,0x2b,0xff,0xaa,0xfb,0xe9,0xf2,0x54,0xc5,0x86,0x4e,0xa9,0x8c,0x39,0xba,0x47, +0x4b,0x22,0x22,0x1f,0x90,0x0f,0x34,0x60,0xb1,0x31,0x5e,0x49,0x87,0x36,0x82,0xc8,0xe7,0xd1,0x97,0x01, +0xca,0x09,0xca,0x68,0x8e,0xca,0xcb,0xa4,0xe3,0xca,0x0f,0x02,0x06,0x4b,0x8c,0xeb,0x1d,0x67,0xbb,0xbc, +0x88,0xe8,0xcb,0xfe,0x3b,0x54,0xf0,0x92,0x19,0xd5,0xc1,0x65,0x5d,0x14,0x37,0x36,0xb4,0x33,0xa1,0xe2, +0x9c,0xcc,0xf3,0x8b,0xd6,0x90,0x10,0x6b,0xb2,0x30,0x04,0x76,0x65,0xfe,0x9e,0xec,0xf4,0x64,0x9b,0x62, +0xcb,0xa5,0x83,0x03,0xea,0xf6,0x0e,0xb2,0xf3,0x58,0x49,0x3b,0x69,0xcb,0xe0,0xbb,0x08,0x5c,0x07,0x48, +0x34,0xba,0xf6,0x35,0x2e,0x03,0x94,0xa4,0xe2,0x96,0x72,0x19,0xa5,0x25,0x6d,0x29,0xb4,0xb5,0xcc,0x60, +0xb1,0xd1,0xbd,0x72,0x04,0x88,0xa3,0xbc,0x5d,0xf4,0xb3,0xa5,0x5f,0x79,0x27,0x99,0x7e,0x26,0xa2,0x09, +0x9e,0x81,0x66,0xa0,0xee,0xf4,0x16,0x62,0x1c,0x20,0x67,0x9d,0x1c,0x86,0xfb,0xea,0xb4,0x95,0x7a,0x53, +0xd5,0x51,0x5b,0x06,0x57,0xd7,0xd6,0x84,0x35,0xa8,0x82,0x39,0xb8,0x06,0x2a,0x46,0xd3,0xb9,0x7f,0x7e, +0xfb,0x46,0x4d,0xc5,0xec,0x5d,0xc0,0xdb,0x85,0x89,0x8e,0x1d,0x46,0xa1,0xa1,0xd1,0x73,0x21,0x80,0xa6, +0x4b,0x55,0x7c,0x01,0x7b,0xfe,0x48,0x0a,0x60,0xaa,0x9e,0x96,0xc8,0x9c,0x23,0x98,0xe7,0x9b,0x78,0x88, +0xd3,0xf2,0x0f,0x42,0x65,0x02,0x9c,0x3f,0x57,0xc8,0x9b,0x3a,0xe2,0x74,0xca,0xd2,0xcd,0xb5,0x8f,0x6f, +0x5e,0xbe,0x81,0x75,0x08,0xdb,0x6d,0xfe,0xb9,0x09,0x43,0x51,0xd8,0x73,0xcc,0xd4,0xda,0x0c,0x3d,0x88, +0x2e,0xe2,0x15,0xb3,0xb3,0xd5,0x30,0x3d,0xa1,0x78,0x77,0x71,0x99,0xc3,0xb5,0x9a,0x85,0xe8,0xcc,0x48, +0xf4,0x28,0x43,0x3f,0xf0,0x00,0x66,0x1f,0x99,0x16,0x4d,0x20,0x48,0x5c,0x9a,0x79,0xc1,0xc3,0x55,0xd5, +0x4d,0x16,0xb3,0x2c,0x8d,0x0f,0xe8,0x55,0xce,0x13,0x3b,0x98,0xd7,0x58,0xe1,0x8b,0x3b,0x56,0x53,0xad, +0x98,0xb0,0x17,0xb8,0x79,0x16,0x22,0xcc,0x50,0xf1,0x41,0x3b,0xbd,0x51,0xab,0xbe,0xaa,0xfe,0xa1,0x9d, +0xbf,0xda,0x94,0xe1,0x4d,0x19,0x8f,0x47,0x1a,0x2c,0xb1,0xea,0x00,0xa6,0x8c,0x3e,0xc3,0xed,0xff,0xec, +0x0c,0xc8,0x54,0x5b,0x6c,0xf0,0x09,0x47,0x6d,0x9a,0x5d,0x8e,0x30,0x30,0x1b,0x2e,0x33,0x31,0xa3,0xd1, +0x7d,0xed,0x40,0x67,0xc3,0x6e,0x83,0x8b,0x9c,0x32,0xd8,0x28,0xe0,0xf0,0x31,0x79,0x99,0xfc,0x11,0x08, +0xc9,0xa9,0x5d,0xe1,0x84,0xcb,0x91,0xcc,0x79,0x6f,0xc2,0x48,0x9d,0x1b,0x74,0x38,0x11,0xc3,0x42,0x9b, +0xcb,0x1a,0xba,0x78,0x04,0x5e,0x46,0x60,0x75,0x2b,0x34,0x68,0x0f,0xc0,0x20,0x67,0x36,0x0f,0x7c,0x1d, +0xf4,0xf1,0x28,0xb3,0xb6,0x86,0x67,0xf4,0x1a,0x55,0x3d,0x00,0xaa,0xc7,0xea,0xca,0xc7,0xe0,0x33,0xb8, +0x52,0xb7,0x3c,0x74,0xdd,0x48,0x9b,0x3e,0x3a,0x17,0x2c,0xf2,0xd3,0x90,0x18,0x01,0xe6,0xbe,0x99,0x0f, +0xd0,0x2b,0xce,0x52,0xe4,0x32,0x7f,0x59,0x48,0xe6,0x97,0x17,0x3b,0xbd,0x9c,0x12,0x2f,0x47,0x01,0x26, +0x1c,0x4b,0xbf,0xfc,0xf6,0xad,0x47,0x2f,0xe1,0x86,0xd2,0x96,0x10,0x52,0xa5,0x21,0x9a,0x07,0x0c,0x35, +0x0f,0xfb,0x70,0xb3,0x64,0xf6,0xd3,0xa6,0x2f,0x7a,0xc3,0x4d,0xb2,0x65,0x01,0x94,0xe4,0x83,0x52,0x1d, +0xf9,0x68,0xfa,0x75,0x99,0x27,0x25,0x9c,0x86,0xdd,0xb5,0x15,0x9b,0x1c,0xba,0x41,0xe3,0x00,0x54,0xaa, +0x8e,0x91,0x27,0x62,0xa4,0x98,0x68,0x65,0x36,0xe3,0x2d,0xd5,0xc0,0xa4,0x81,0x91,0xcb,0x48,0x53,0x5c, +0xb4,0x4c,0xde,0xda,0x1f,0x96,0x23,0x6d,0x63,0xf7,0x04,0x16,0x18,0xd8,0x62,0x20,0x7a,0xc8,0x8c,0x88, +0xf6,0x04,0x09,0xe3,0x9a,0x09,0x76,0x1b,0x95,0x40,0x31,0x9e,0x8a,0xbd,0xf9,0x53,0x25,0x6a,0x88,0xab, +0xe7,0x62,0xa5,0x2d,0x21,0xea,0xae,0xba,0x30,0xb2,0xf9,0x4b,0xb8,0x72,0xae,0x25,0x45,0xfa,0x10,0xfd, +0xbb,0x2e,0xd0,0x32,0x05,0x8e,0xc5,0x8c,0x1f,0xd9,0xd7,0xc6,0x68,0x79,0x0c,0x1c,0x2e,0x1c,0x93,0xe8, +0x3a,0x9c,0x99,0x18,0x35,0x55,0xc8,0xd1,0x6c,0xcb,0x46,0x8a,0x1f,0x8e,0xbe,0xd2,0x0e,0xd5,0x6a,0x3a, +0x98,0x6f,0x1e,0x1d,0xe0,0xc1,0xb9,0x22,0x63,0x8c,0xec,0x60,0xbc,0xb7,0xb9,0x86,0x7a,0xa2,0xa2,0x13, +0x5a,0x36,0x14,0x3b,0xc2,0x3e,0x51,0x8d,0x53,0x82,0xe3,0xaa,0xea,0xb7,0xaf,0xea,0xbe,0x26,0xee,0x90, +0x6c,0x44,0x81,0x97,0xb7,0x61,0xfd,0xd0,0x66,0xe1,0x95,0x17,0x5c,0x25,0x13,0x34,0x26,0x27,0x0b,0xb9, +0x41,0x89,0x52,0xbf,0x6b,0x9b,0x56,0x07,0xa7,0x91,0xf6,0x42,0x8f,0xe4,0x2d,0x20,0x65,0x9f,0x66,0x8c, +0x7c,0x41,0xf1,0xf8,0x00,0x98,0x24,0x17,0x5d,0xcc,0x24,0xf6,0x0c,0x75,0x29,0x25,0xf3,0x18,0xe8,0x4d, +0x23,0x84,0x47,0x4c,0x83,0xd9,0xd0,0xeb,0x5d,0x71,0x80,0x19,0x8d,0xcd,0x22,0x4e,0xd5,0x9b,0xd2,0x6b, +0x9b,0x45,0xbc,0x09,0xb8,0x6a,0x7c,0x1e,0x8f,0x97,0x53,0x60,0x29,0xcf,0xa3,0x74,0xd2,0x74,0xd5,0x9b, +0x8c,0xa7,0xa7,0xe7,0x13,0x3c,0xa5,0xe8,0xcd,0xc9,0x70,0xc2,0xc8,0x9f,0x76,0x8b,0x5c,0x02,0xda,0x3b, +0xe5,0x9a,0x51,0x78,0xe0,0x6c,0x18,0xfd,0xa5,0x99,0x9d,0x81,0xa9,0x80,0xaf,0x91,0xe2,0x69,0xc2,0xf3, +0xcc,0x72,0x1c,0x40,0xe7,0x6d,0x9c,0x2e,0x05,0x33,0x0e,0x43,0x44,0x3e,0x16,0x8c,0xd0,0x3a,0x1e,0x3f, +0x85,0x32,0xc5,0xbf,0x23,0x57,0xc6,0x37,0x01,0xfc,0x94,0xa4,0x9f,0x9b,0x80,0x34,0xa9,0x07,0x0c,0xd5, +0x87,0x28,0x8d,0xe7,0xdc,0x7a,0x77,0x81,0xbf,0xab,0x9b,0x8f,0x81,0x90,0x8a,0xaf,0xa3,0xea,0x81,0x1b, +0xbb,0x86,0x3e,0x41,0x7b,0x6d,0x53,0xaa,0xc1,0x33,0x52,0xc5,0x62,0x27,0x35,0x74,0x31,0x16,0x64,0x87, +0xf6,0x50,0xca,0xa9,0x89,0x67,0x30,0x18,0x84,0xd3,0x68,0x7e,0x4a,0x1e,0x87,0x9f,0x03,0x3f,0x40,0x3e, +0x21,0x0b,0x1b,0x44,0xf1,0x10,0x1a,0x43,0x4e,0xc6,0x07,0x24,0x78,0xc5,0x0b,0x88,0x29,0x7c,0x66,0x0c, +0xcb,0xb6,0xb7,0xb6,0x03,0x9c,0xdc,0x85,0xf2,0x59,0x4b,0x7b,0x6c,0x2b,0x02,0x86,0x5d,0x68,0x5f,0x09, +0xc8,0x14,0x20,0xbb,0x8b,0xce,0x94,0x44,0x02,0x4a,0xc8,0x96,0x6b,0xcf,0x62,0x09,0x40,0x66,0xd2,0xf5, +0x00,0x3d,0x65,0xc1,0x9d,0x1c,0x48,0x18,0x24,0x72,0xee,0xb2,0x74,0x73,0x0d,0x6a,0xcb,0x2b,0x8e,0x89, +0xf2,0x85,0x70,0x5d,0x06,0xc8,0x0b,0x1e,0xf5,0x00,0x84,0x85,0x64,0x47,0x39,0x86,0xce,0x16,0x17,0xe4, +0xc3,0x8c,0xd1,0x46,0x9d,0x4c,0xab,0x9f,0x4a,0xa8,0xfc,0xe7,0xf4,0x15,0xf1,0x0a,0x8a,0xa6,0x2e,0x17, +0xa2,0xcb,0xa6,0xaa,0x00,0x87,0x9e,0xc1,0x40,0x43,0xd0,0x88,0xda,0xb1,0x12,0x96,0x76,0x92,0x9c,0x49, +0x6e,0x23,0xb3,0x04,0x55,0x04,0x64,0x2d,0x89,0x94,0x04,0x28,0x92,0x15,0xab,0x48,0x06,0x15,0x4e,0xbe, +0xc0,0xa2,0x5d,0x45,0xb3,0x49,0x3c,0x7f,0xc7,0xec,0x79,0x4d,0x98,0xcd,0xca,0x07,0x05,0x2e,0x01,0x24, +0xc1,0xf0,0x41,0x65,0x02,0xd5,0xd2,0x66,0xd7,0x39,0x9c,0x01,0xb7,0xaf,0xc2,0xeb,0x9e,0xd3,0x59,0x1a, +0xcb,0x75,0xa8,0x57,0x05,0xd7,0xe4,0x7a,0x4d,0xde,0x77,0xe2,0xfe,0x50,0x38,0x46,0x2d,0xde,0x09,0xe1, +0xf2,0x2b,0x0a,0x15,0xd6,0x83,0xdb,0xdb,0xe8,0x8b,0x78,0xca,0x43,0xa5,0x01,0x55,0x4b,0x8e,0x42,0x47, +0x32,0x1a,0x23,0xdf,0xd0,0xcc,0x0b,0x6c,0xf7,0x7a,0xed,0x7e,0x6f,0x33,0xe6,0x17,0x4c,0xd9,0x24,0x2a, +0x72,0xe0,0x72,0xc3,0x13,0x14,0x8d,0x6e,0xa0,0x37,0xa4,0xd7,0xff,0x00,0x43,0xc6,0xc8,0xd1,0x56,0x1b, +0x5b,0x64,0x2c,0xe6,0x1b,0xa5,0x9b,0xd5,0x90,0xa1,0x6e,0x56,0xbb,0x7d,0x8d,0x03,0xab,0xea,0xe8,0xb2, +0xa7,0xe7,0x0e,0x0c,0x50,0x47,0x60,0xe3,0xb1,0x15,0x28,0x9d,0xe5,0x18,0xff,0x58,0x8e,0x9c,0xb3,0x1c, +0x92,0xd9,0x5d,0x50,0x1b,0x30,0x34,0xc8,0xd1,0x26,0x87,0x24,0x11,0x1a,0xea,0x18,0x53,0xe4,0x00,0x09, +0xb6,0x9c,0xc7,0xbf,0x67,0x8e,0xdc,0xa1,0x0e,0x9a,0xfa,0xab,0xe7,0x89,0xaa,0x4d,0x71,0x73,0x7c,0x24, +0x73,0xaa,0x6b,0xaa,0x94,0x34,0x55,0x64,0xb9,0xd5,0x73,0xa5,0xaa,0xc7,0x31,0x59,0x52,0x39,0x59,0xca, +0x20,0x32,0x5a,0x75,0xcf,0x16,0xdc,0x4c,0x22,0x35,0x5b,0x44,0x98,0xbd,0x98,0xfd,0x7a,0x89,0xd7,0xba, +0x91,0x57,0xf0,0x7b,0xcf,0xc0,0x9b,0x93,0x72,0xef,0x50,0xee,0x55,0x79,0xdb,0xe3,0xf3,0xd6,0x59,0x37, +0xfb,0x77,0x0c,0xa3,0xfa,0x54,0xcc,0xe4,0x74,0xf8,0x4e,0x3d,0x0e,0x3e,0x27,0x7a,0x08,0xf9,0x62,0x82, +0x73,0x26,0xbb,0xef,0x7c,0xc5,0x58,0xbd,0x62,0xbe,0x66,0xae,0xf9,0x2a,0x09,0x52,0x9b,0xb0,0x92,0xfa, +0xce,0x92,0x34,0x63,0xdd,0x45,0xf5,0xf9,0x03,0x14,0xd5,0xe7,0xac,0x1a,0x2a,0xaf,0xde,0x25,0xd7,0x79, +0x7a,0xd3,0x1d,0xfc,0x2e,0x47,0x6c,0x90,0x55,0x73,0x12,0xb5,0x20,0xe9,0x88,0x2d,0xcc,0x29,0x49,0x1c, +0xa6,0x6b,0x3e,0xae,0xc3,0x8c,0x84,0x9d,0xbe,0xd2,0xaa,0x51,0xd0,0x72,0xac,0xab,0xb3,0x47,0xa8,0xdb, +0x48,0xf1,0x20,0x69,0xdd,0xa8,0x93,0x2a,0x35,0x0e,0x9e,0x2e,0xbe,0x24,0x67,0x52,0xd5,0x48,0x3f,0x2b, +0x32,0x83,0x01,0x09,0x22,0x8b,0x90,0x8c,0xa8,0x2e,0xc2,0xa8,0x51,0x0f,0xab,0xd0,0x29,0x71,0x95,0xa5, +0x2c,0xa5,0x18,0x48,0x56,0x3c,0xe0,0x40,0x17,0x7b,0xac,0x2c,0x10,0xe7,0xe8,0x28,0x89,0x93,0x38,0xe8, +0x06,0x79,0x03,0x66,0xda,0xff,0x84,0x27,0xe4,0xc0,0x7b,0xff,0xce,0x0b,0x80,0x86,0x66,0xda,0xcb,0x97, +0xde,0x35,0xeb,0x2a,0xd1,0x9b,0x41,0x37,0x29,0x98,0x51,0xbf,0x93,0xea,0x4b,0x24,0xf9,0xcb,0x8a,0xdd, +0x88,0x0c,0x2d,0x18,0x35,0x64,0xd5,0x23,0x97,0x35,0x6e,0x9c,0xd1,0x3c,0x78,0x57,0xd6,0xc8,0x31,0xbc, +0x7b,0xad,0xaa,0xf7,0x48,0x8d,0x7d,0x40,0xcb,0xe4,0xe8,0x98,0x54,0x38,0xcc,0x51,0x44,0x1d,0xad,0xee, +0x74,0x81,0xa1,0xba,0x72,0x31,0x96,0x19,0x7d,0x2b,0x0d,0x2e,0x1a,0xe7,0xdc,0x18,0x67,0x43,0x63,0x48, +0x3d,0xeb,0xe3,0xb8,0x09,0x86,0x20,0xc3,0x40,0xda,0x65,0x03,0x2c,0x3d,0xfb,0x1b,0xc0,0x0b,0x4c,0xa9, +0x89,0xb4,0x94,0x5a,0x40,0x1d,0xf6,0xe4,0xbc,0xa8,0x81,0x2b,0x6d,0x01,0x03,0x9c,0x62,0xb0,0xd5,0x11, +0xd1,0x55,0x0b,0xea,0xf0,0x27,0x49,0x7a,0xd1,0x80,0x3c,0xeb,0x1f,0x18,0x45,0xb2,0xf4,0x04,0x25,0x93, +0x68,0xcb,0x6b,0xcf,0x72,0x79,0x95,0xba,0xb6,0x26,0x83,0x62,0x1d,0xad,0x35,0xac,0xb8,0xb7,0x15,0xeb, +0x58,0x9b,0x0a,0x15,0xb3,0xf7,0xfb,0x27,0x82,0xe0,0x23,0x73,0x27,0x1f,0x99,0x39,0xf9,0xc8,0xac,0x91, +0x8f,0xac,0xa6,0x12,0x74,0x85,0xb4,0xb8,0xa1,0xe7,0xfa,0x16,0x91,0xd7,0xb6,0x08,0x83,0x78,0x15,0x1d, +0xea,0xb4,0xdb,0xcb,0xe6,0x59,0xbe,0xff,0xea,0x99,0xc1,0xb9,0x9d,0x62,0xa2,0x9b,0x68,0xb1,0x22,0x5a, +0x59,0x81,0x42,0x79,0xf7,0x21,0x8a,0x84,0x2d,0x2b,0xc2,0xa4,0x3a,0x56,0xdc,0x48,0x5d,0xf6,0x4a,0xe9, +0xb4,0xe7,0x5f,0xce,0xe2,0x78,0x4e,0x08,0x7e,0x80,0xe3,0x24,0xce,0x5b,0x57,0xc5,0x3c,0x21,0x2f,0xbd, +0xde,0x65,0x3e,0x1d,0x2f,0x3c,0xe1,0x5f,0x83,0x53,0x97,0xba,0xaf,0x08,0x9b,0x59,0xa9,0x55,0xe5,0x49, +0x25,0x0f,0x0c,0xaa,0x87,0x4f,0x34,0x43,0xfd,0x92,0x4c,0x38,0xc0,0x1d,0x19,0x5a,0x19,0x50,0x4c,0x3a, +0xba,0x11,0x8e,0x73,0x3c,0xe5,0x53,0x7e,0xd1,0x21,0xb0,0x19,0x6b,0xb4,0x36,0x36,0x2b,0xa2,0xe7,0xad, +0xe2,0x99,0x0a,0x0a,0x46,0x5d,0x8a,0x21,0x8e,0xcd,0xcb,0xba,0xc4,0xa3,0x6a,0x99,0xd1,0xb1,0x07,0x71, +0xef,0xd0,0x1c,0xbf,0xd3,0xd2,0x1e,0x3c,0x18,0xb7,0x6f,0xdf,0x5a,0x34,0xcd,0x51,0xe1,0xbc,0x70,0x8e, +0x97,0x1c,0x28,0x63,0x98,0x50,0xc4,0x1f,0x54,0x05,0xff,0xac,0xae,0x8b,0xd6,0x82,0x2b,0xfe,0xc1,0xfd, +0xf6,0x1d,0x93,0xf7,0xf5,0xc1,0xdf,0x7f,0xd7,0xe4,0x85,0xf2,0x7f,0xf6,0xe4,0x9d,0x15,0x17,0xbf,0x7b, +0xf2,0xd2,0x37,0x89,0x7d,0xd4,0x0e,0xf2,0xc3,0x13,0xb8,0x09,0x75,0x67,0xb8,0x83,0xb4,0x61,0x5a,0x57, +0x5b,0x4b,0xbf,0x87,0x19,0x45,0x53,0xc6,0x05,0x89,0xd9,0x5c,0xf3,0x0e,0x10,0x45,0xf9,0x50,0x7d,0xc2, +0xc1,0xe8,0xa7,0xf1,0xdc,0xda,0x6f,0x4f,0x45,0xaa,0x45,0xfb,0x9d,0x1e,0x87,0xfb,0xd1,0xf7,0x5a,0xe7, +0x20,0xed,0xa0,0x33,0xfe,0x78,0x88,0xbe,0x7d,0xe0,0xef,0xf7,0x3f,0x04,0x70,0xb5,0xdf,0x58,0x16,0xf1, +0xc7,0x59,0x82,0x3a,0x15,0xad,0xa8,0xd3,0x09,0xe0,0x13,0x66,0xfb,0xc6,0x06,0xfc,0xf6,0x7d,0x21,0x41, +0x8e,0x3b,0x51,0x60,0xb8,0x8b,0x73,0x69,0x77,0x09,0x81,0x62,0x69,0x4d,0xd0,0xf4,0xe6,0x09,0x9a,0x56, +0x8a,0xd6,0x06,0x8d,0xb8,0xb7,0x2c,0x85,0x94,0x11,0x48,0x90,0x58,0x41,0x82,0x8f,0x3f,0x3a,0x45,0x9a, +0x0f,0x94,0x04,0x23,0x93,0x3f,0x8d,0x86,0x89,0xe4,0x0c,0xd1,0x09,0x6f,0x12,0x4c,0xa0,0x74,0x51,0xe7, +0x2c,0x78,0xae,0x00,0x4b,0x6e,0xee,0xf7,0xf3,0x6a,0x1a,0x36,0x83,0x18,0xab,0x96,0xe5,0x37,0xe2,0x90, +0x9a,0x48,0xf9,0x8e,0x18,0x55,0x3c,0x95,0xa0,0xca,0x89,0x31,0xdf,0xc5,0xd0,0x7a,0x1c,0x31,0x90,0xd1, +0x8e,0x09,0x6d,0x9d,0xdd,0xe3,0x6b,0xd0,0x9d,0xd8,0xbd,0x44,0xb2,0x7b,0x5a,0xeb,0x89,0xc1,0xef,0xe5, +0x67,0xe3,0x9f,0xe2,0x28,0xaf,0x0f,0xac,0x35,0x62,0x34,0xb6,0xf2,0x48,0x8c,0xcd,0x09,0x0d,0x75,0xa0, +0x3c,0x33,0xe5,0xd1,0x2a,0x35,0xda,0x74,0x12,0xbc,0x25,0x4a,0x19,0xb2,0x9e,0xc1,0x69,0xe8,0x5a,0xca, +0xc0,0xe5,0x65,0x96,0x4f,0x35,0xb9,0xfb,0xfd,0x90,0x39,0xa3,0x4a,0xfe,0x00,0x6c,0xd0,0xb1,0xc4,0xef, +0xc4,0xa5,0x20,0xf7,0xba,0x77,0xc7,0x44,0xe8,0x9e,0xf1,0x42,0xba,0x36,0xef,0xf9,0xfb,0x67,0x63,0xf4, +0x74,0x62,0x6c,0xcc,0x39,0xa7,0xe1,0xaa,0x9f,0xc7,0x53,0x6c,0x54,0x2e,0xfc,0xa0,0xd4,0x01,0x6e,0xb3, +0x1b,0xc3,0x46,0xa1,0xa2,0x7a,0xaf,0xd5,0x56,0x2a,0x71,0xbf,0xe9,0xdd,0xae,0xc9,0xb2,0xcf,0x01,0x15, +0xae,0xe5,0x88,0x4e,0x07,0x11,0xbe,0x32,0x50,0xf3,0xd1,0xb5,0xd1,0x8a,0xbc,0x0e,0x43,0x27,0x3a,0x3c, +0xd5,0x8c,0xab,0xb0,0x9c,0xc4,0x8d,0x65,0xc4,0x8c,0xb0,0x0b,0xf1,0x6c,0x6b,0x2c,0x55,0x30,0x19,0xcd, +0x32,0x38,0x27,0x80,0x60,0x06,0xff,0x2c,0x68,0x8f,0x02,0x91,0x6a,0xa0,0x34,0x8d,0x22,0xe1,0xf8,0x01, +0x7d,0x5e,0x9d,0x90,0x22,0x6c,0xc5,0xe4,0xe2,0xc3,0x82,0x4c,0x1e,0x12,0xc0,0x05,0x1c,0x63,0xf8,0x06, +0x86,0x30,0xec,0xe3,0xa2,0x4d,0x31,0xdb,0xbb,0x5a,0xa6,0x65,0xb3,0x52,0x26,0xe5,0x3c,0xd6,0x6d,0x56, +0x3c,0xa9,0xef,0x5e,0xd5,0x12,0x77,0x65,0x1a,0x54,0xd7,0xe1,0x28,0x6b,0xea,0x49,0x95,0x2a,0x08,0xcb, +0x6b,0xf6,0x12,0xdc,0xfd,0x1c,0xd3,0x8d,0xbd,0x0b,0x64,0x7b,0x61,0xfb,0x9f,0x60,0xf7,0x9b,0x11,0x99, +0x79,0xd0,0x5b,0xe9,0x65,0x3c,0x26,0x25,0x65,0x7c,0x1c,0x45,0x17,0x1a,0x42,0x5f,0x86,0x44,0x3a,0x91, +0xf9,0x34,0x20,0xa4,0x56,0xeb,0x95,0x17,0x4d,0xcc,0x5e,0x28,0x0d,0x1b,0x09,0xa0,0xf2,0xa1,0x27,0x91, +0x34,0x20,0x0d,0x0d,0x3d,0x33,0x7a,0xa6,0xca,0xa2,0x09,0xfb,0x71,0x63,0x20,0xed,0x99,0x99,0x1e,0x94, +0x09,0x3d,0x18,0x9c,0xbd,0x6c,0x99,0x92,0x6b,0xc7,0xd2,0x17,0x29,0x79,0x74,0xf9,0x77,0x76,0xb6,0x2a, +0xd0,0xb6,0xef,0x73,0xac,0x42,0xcc,0x86,0x25,0x34,0x4f,0xcf,0xa3,0x2f,0xbc,0x9c,0xbc,0xa0,0xdf,0x7f, +0x02,0x78,0x01,0x08,0x57,0x49,0x23,0x0b,0xbc,0xac,0x81,0xa2,0xc9,0xfd,0xb3,0xd1,0xfe,0xed,0xb9,0x19, +0x8c,0xea,0x2e,0xf8,0xe7,0x08,0x9d,0x2c,0x50,0x47,0x80,0x5d,0xe0,0x26,0xae,0x4c,0xee,0x4c,0x9c,0xd3, +0x91,0x0c,0x5a,0x19,0x90,0xfd,0x43,0xa5,0xb1,0x9d,0x77,0x67,0x61,0x76,0xd4,0x3b,0xde,0x42,0x5b,0x9f, +0xbc,0x5b,0xc0,0x47,0xff,0x78,0x0b,0x98,0x13,0xf8,0xb8,0x80,0x8f,0x6d,0xfe,0xb8,0x07,0x8a,0xcc,0x25, +0xa1,0x05,0x33,0xe2,0xa7,0x31,0xf0,0x3a,0x25,0x6a,0xbc,0x3d,0xee,0x68,0x51,0x45,0x12,0x3a,0x7b,0x0d, +0x00,0x71,0x7b,0xa7,0x4e,0xab,0xa3,0xb1,0x22,0xb5,0xe0,0x5d,0xed,0x36,0x14,0x03,0xed,0xaa,0x5f,0x65, +0xea,0x75,0x4b,0xe6,0x47,0xce,0x5c,0xf9,0x1d,0x46,0xe4,0xf0,0x05,0x59,0x21,0x99,0xa5,0xee,0x01,0x82, +0x45,0x22,0x10,0xed,0xe6,0xa7,0x61,0x57,0x49,0xde,0xeb,0x73,0x56,0xcb,0xac,0x18,0xcb,0x88,0x2e,0xa5, +0xbc,0x94,0x92,0xb3,0x44,0xab,0x4b,0x7b,0x4c,0x15,0x78,0xb8,0x1f,0x52,0xb5,0x57,0x38,0xe3,0xfd,0x95, +0x1f,0xd3,0x70,0x37,0x90,0x0f,0xa5,0x6a,0xb2,0xeb,0x6f,0xa7,0xe2,0x1d,0xd6,0xd3,0x25,0xc1,0x4e,0xdc, +0x55,0xae,0x13,0x79,0x25,0xa5,0xac,0x16,0x1a,0xca,0x15,0x0e,0x78,0x6f,0xd7,0x96,0x8a,0x26,0x6d,0xb0, +0x5b,0xa9,0x89,0x9f,0xc4,0x50,0x49,0x0b,0x8a,0x3a,0x5e,0xb5,0x87,0xbc,0x28,0xd0,0xa0,0xab,0xdf,0xd5, +0xb9,0x27,0x2b,0xac,0x04,0x1b,0x4d,0x95,0x9a,0xaf,0x66,0x51,0x60,0x95,0x32,0xbf,0xad,0x06,0x94,0x59, +0xc7,0xed,0x50,0xd6,0xc0,0xb5,0x0f,0x47,0x9d,0xf7,0xc0,0xda,0x2a,0x66,0x25,0x58,0x6d,0x08,0xfd,0x8d, +0x7a,0xe5,0x6e,0x2d,0x8f,0xe8,0xd8,0x97,0x87,0x00,0xbe,0x5e,0xdb,0x8b,0x52,0x3d,0x6a,0x0b,0x9e,0x15, +0xd5,0x51,0x48,0x17,0x24,0xf2,0xab,0x15,0x5a,0x41,0x29,0x87,0x2c,0x2d,0x3d,0x19,0xd5,0xac,0x39,0x87, +0xdd,0x7d,0x74,0x8c,0x32,0xec,0xfa,0xa3,0xe5,0x4b,0xc1,0xbf,0x66,0x1f,0x21,0xb7,0x78,0x42,0x31,0x41, +0x7d,0xa7,0x44,0xd3,0xe0,0xe9,0xfc,0xc8,0x87,0x19,0x3a,0xba,0x94,0x1a,0xe2,0x90,0x36,0xd4,0x3b,0xcd, +0x6f,0x73,0x38,0xab,0x3b,0x5e,0x1b,0xef,0x0c,0xf8,0xac,0x3d,0x49,0x60,0xa7,0x25,0x7b,0x9d,0x24,0x9d, +0xc5,0x79,0x82,0x5a,0x7a,0x34,0xa7,0x48,0xe7,0x30,0x59,0x88,0x5d,0x9a,0x2f,0x1c,0xc6,0x39,0xfd,0x90, +0x1e,0x5a,0x59,0xe4,0x2e,0x7c,0x04,0x0d,0xe7,0xe2,0x80,0x41,0x45,0x25,0x0f,0x5d,0x03,0x95,0x8b,0x01, +0xc6,0xa0,0x81,0x1d,0x66,0xde,0x4d,0x91,0x56,0xbe,0x09,0x51,0xc6,0xf3,0x34,0x2e,0x05,0x0c,0x35,0x8c, +0x66,0xf6,0xb5,0xf5,0x0a,0x89,0xa1,0x58,0x3d,0x4a,0x6b,0x5c,0x6e,0x23,0x2a,0xc1,0x5e,0xc8,0x6c,0xc8, +0x24,0x96,0xac,0x00,0x8e,0xc2,0x68,0xe4,0xed,0xbd,0x7f,0xf7,0xee,0xc5,0xde,0xe1,0x8b,0xe7,0xde,0xc0, +0x7b,0xf7,0xfe,0x70,0xad,0xfa,0x86,0x32,0x69,0xb9,0x70,0x14,0x39,0xf8,0xc7,0xbb,0xbd,0x87,0x12,0x5e, +0x7c,0xe0,0xc6,0xba,0x40,0xb7,0x69,0x82,0x46,0xd1,0x14,0xc3,0xa3,0x23,0xa5,0x26,0x16,0x2a,0xc1,0x69, +0x38,0xf9,0xfe,0x49,0x6f,0xa8,0xa5,0x4f,0x84,0x7d,0x28,0xc1,0x2f,0x57,0x67,0x2f,0x20,0x7b,0xfb,0x91, +0x99,0xbd,0xfd,0x48,0x65,0xcf,0xc2,0xc9,0x30,0x0a,0x67,0x6d,0x6f,0xb2,0x56,0xd9,0x99,0x2e,0xc8,0xf0, +0x74,0xa6,0xa5,0x2c,0x29,0xe5,0x5c,0x4b,0x39,0xa5,0x94,0xc2,0xbb,0xc6,0x5a,0xce,0x82,0x69,0x70,0x6e, +0x2b,0x8d,0xa8,0x21,0x1e,0x9e,0x6b,0x56,0x9c,0x2d,0xc3,0xd0,0xee,0xdc,0xb4,0xb2,0x3b,0xb7,0x1f,0x60, +0xa2,0xa6,0xc7,0x15,0x69,0x77,0xe7,0xaa,0x03,0xcf,0x3d,0x5c,0x8f,0x83,0xd6,0x99,0xca,0x5c,0xe4,0x64, +0x90,0xe7,0x79,0xc1,0xb4,0x4a,0xc3,0x60,0x15,0x9c,0xc8,0x85,0xce,0xda,0x51,0x7b,0xea,0x8b,0x05,0x74, +0xd1,0x34,0x63,0x87,0x17,0x7a,0x77,0xce,0xc2,0x0b,0x47,0x13,0x17,0xf5,0x26,0x2e,0xf8,0xc8,0x15,0x6d, +0x50,0x13,0x97,0xa1,0x2d,0xae,0xae,0x1a,0xb9,0xd4,0x1a,0xb9,0x14,0x47,0x39,0x45,0x01,0xb9,0xd2,0xde, +0x92,0x22,0xbe,0xde,0x53,0xbc,0xda,0xc8,0x57,0xb7,0x73,0xed,0xb8,0x39,0xa2,0x40,0x41,0x0f,0x49,0x5b, +0xc1,0xf5,0xc2,0x15,0x1d,0xa5,0xc7,0x8d,0x3a,0x22,0x66,0x40,0xdc,0x88,0x57,0xf2,0x38,0xc4,0x32,0xc1, +0xd7,0x50,0x7f,0x67,0xbd,0xa2,0x4b,0xda,0x95,0x78,0xb1,0x1c,0x8c,0xe5,0xdb,0x25,0xfa,0x02,0xd6,0x59, +0xe9,0xb1,0x83,0x95,0x56,0xfc,0x3f,0x46,0x27,0xb3,0x0d,0xd4,0x49,0x11,0x1f,0x25,0xf7,0x5f,0x0d,0x23, +0x75,0x93,0x66,0x15,0x08,0xf7,0x4e,0xdc,0xf9,0xcb,0x15,0xaf,0x55,0x8d,0x65,0x15,0x65,0xca,0x46,0xb2, +0xc8,0x70,0x2c,0x36,0x65,0x3e,0x33,0x65,0xf6,0x42,0x5d,0x53,0xc1,0xe8,0xfe,0x67,0x77,0xf7,0x9b,0xfa, +0xbc,0xc7,0x7d,0xfe,0x7c,0xc4,0x3e,0x23,0xab,0xe1,0xd7,0x9e,0x22,0xcc,0x29,0x40,0x78,0x1c,0x32,0x1e, +0xfb,0xe1,0x21,0xfb,0xc4,0x45,0x3f,0x82,0x07,0x21,0xea,0x6c,0xee,0x8f,0x0e,0x59,0x2b,0xb3,0x7d,0xd8, +0x5d,0x42,0x0d,0xc5,0xc0,0x72,0xa9,0xb0,0xef,0x07,0xbb,0xf6,0x3a,0x56,0x20,0x40,0x35,0x6b,0x36,0x0d, +0x77,0x09,0xc1,0x03,0xeb,0x25,0x61,0x57,0x6d,0xea,0xea,0x87,0x60,0x38,0x0f,0x8d,0xb7,0x85,0x6b,0xd1, +0x25,0x44,0xfa,0x4b,0x18,0x29,0x21,0xaa,0x2e,0xfa,0xfb,0x52,0xef,0xdf,0x07,0xea,0x9f,0x9a,0x29,0x42, +0x18,0xc5,0xb8,0x11,0x6a,0xd2,0x74,0xee,0x43,0xf5,0x1e,0xe6,0x84,0x21,0x94,0x3e,0x18,0x68,0x3c,0x87, +0x3b,0x14,0x5c,0x68,0xaa,0x36,0x9f,0x73,0x9b,0x6f,0xc2,0xe7,0x7a,0x9b,0xf6,0xed,0xe8,0x48,0xdc,0xeb, +0x91,0x36,0x6f,0xba,0xc9,0x04,0xc9,0x73,0xa4,0xdd,0xe8,0x39,0x9d,0x7f,0x8b,0x85,0x88,0x08,0xbe,0x61, +0x6f,0xce,0xfa,0x7c,0x82,0x53,0x20,0x7d,0x4a,0x38,0xd0,0x65,0x6d,0x98,0xb6,0xdb,0xbe,0x2e,0xe9,0x40, +0xb7,0xbf,0x6c,0xa2,0xbc,0xca,0x68,0xd0,0x47,0x07,0xaa,0xa6,0x25,0x62,0x5d,0xd9,0x58,0x5d,0xd0,0x51, +0x51,0x8d,0xf5,0xc9,0xa5,0x24,0x25,0x28,0x87,0x96,0x41,0xb4,0xf1,0xd6,0xcf,0x3b,0x6d,0x4b,0x13,0x05, +0x99,0x36,0xce,0x41,0x19,0x7a,0x65,0xbe,0x8c,0xeb,0x45,0x95,0xd1,0x9e,0x4f,0xbe,0x02,0x9b,0xc4,0xf8, +0x35,0xe0,0xa1,0x14,0xea,0xea,0xf9,0x15,0xde,0x1e,0x39,0xcb,0x8c,0xac,0x7c,0x71,0x63,0xf6,0x87,0x9a, +0x1a,0xf3,0xba,0xe6,0x7a,0x16,0xf8,0x85,0x94,0xb8,0x74,0x0c,0x89,0x86,0xaa,0xa8,0x25,0xb9,0x0b,0x43, +0xc9,0x70,0xbb,0x5d,0x29,0xd9,0xeb,0x66,0x08,0x21,0x01,0x53,0xae,0x52,0x27,0x57,0x86,0x14,0x46,0x26, +0xa6,0x04,0xda,0xdd,0xbc,0xca,0xc1,0x94,0xa0,0xb1,0x27,0x01,0xea,0xa6,0xf7,0x05,0x1a,0x9d,0xce,0x2a, +0x34,0x28,0xb7,0x09,0x0d,0x91,0xe9,0x40,0x43,0xe4,0xdc,0x80,0x06,0x46,0x55,0x35,0xc5,0xf1,0xbf,0xe4, +0xba,0x28,0xfe,0xc8,0xbb,0x44,0x16,0x5a,0x99,0xa2,0x79,0x52,0xc5,0x14,0xbd,0x9e,0xce,0xbc,0xe3,0x21, +0x29,0x9f,0xe7,0x68,0x84,0x89,0xf1,0x42,0x5c,0x12,0x14,0x84,0x20,0x83,0x6b,0x60,0x86,0x7f,0xd9,0xff, +0x89,0xbc,0xd0,0x06,0x22,0x51,0x05,0x22,0x0c,0x63,0xf5,0x13,0xe7,0x3e,0xb2,0x85,0xc5,0xc0,0x0b,0xb5, +0xe4,0x11,0xb5,0x74,0x59,0x54,0x45,0x00,0x35,0x80,0x19,0xb8,0xd2,0x07,0x9a,0xb7,0x23,0x41,0xb8,0xc3, +0x0c,0x1b,0x8f,0x59,0x9c,0x20,0x3a,0xa9,0xec,0xe9,0x38,0xa0,0xa3,0x08,0xf8,0xa4,0x8c,0xeb,0xb0,0x8b, +0xac,0x51,0xaf,0xa2,0x9a,0x0c,0xae,0xac,0x90,0x2e,0x14,0xd0,0xd8,0xe1,0x92,0x58,0xa8,0x3a,0xc3,0xb1, +0x2e,0x74,0x9e,0x4f,0xe7,0x19,0x45,0x1d,0x14,0xdf,0x44,0x8e,0x8f,0xf1,0xf8,0x00,0x7e,0xc7,0x65,0x4b, +0x76,0x82,0x62,0x53,0x4a,0x98,0x6e,0x96,0x8a,0x9b,0xc7,0x4a,0xcd,0x75,0x23,0x3c,0xe0,0xd6,0xa7,0x74, +0x6b,0x1a,0x78,0x9f,0x30,0x5c,0xb9,0x96,0x98,0x73,0x62,0x6e,0x24,0x96,0x9c,0x58,0xe2,0xca,0x83,0x85, +0xa2,0x4b,0xf0,0x4a,0x8a,0x75,0x4e,0xd1,0xd6,0x34,0x29,0xa7,0x2e,0x98,0xd5,0x0c,0x88,0xd0,0x33,0x5d, +0x94,0x97,0x05,0x85,0x11,0x62,0x96,0x1e,0x97,0x6a,0x3d,0xb9,0xa0,0x74,0xd8,0x11,0x2a,0xbe,0x1f,0x06, +0xc1,0x18,0x20,0x39,0x4b,0x62,0xbf,0xde,0xd6,0x61,0x26,0x3c,0x26,0x21,0x80,0x7f,0xe5,0x2c,0x67,0x99, +0xf1,0x42,0x2d,0xc4,0x83,0x31,0x41,0x03,0x25,0xad,0x5b,0xef,0x07,0x9a,0x74,0x22,0xd0,0x6f,0xfb,0xca, +0xbb,0x16,0x06,0x36,0xa8,0xae,0x0e,0x3d,0x9a,0xb3,0x18,0x97,0xd6,0x30,0xcc,0xa9,0x8c,0x90,0xc5,0x6f, +0x69,0x86,0x2c,0x3e,0xd9,0x10,0x39,0x50,0xc2,0x16,0x68,0x58,0xc8,0x54,0xe0,0x17,0x5e,0x5a,0x7a,0x01, +0xdf,0x0a,0x1e,0x90,0xdb,0x3e,0x74,0x67,0x02,0x1b,0x79,0xa3,0x17,0xe7,0x26,0xb9,0x33,0x30,0x1e,0x0b, +0x34,0x0f,0xac,0xcb,0x2e,0xab,0x2b,0x01,0xb1,0x27,0x68,0x30,0x3c,0x52,0xbf,0x06,0x65,0xf7,0x72,0x96, +0x9c,0xd2,0x33,0x1f,0xde,0x9d,0xfa,0x3f,0x68,0x36,0x6e,0x6b,0x66,0x08,0x2d,0x7a,0xba,0x83,0xad,0x44, +0xf7,0x3b,0x6b,0xb8,0x7d,0x0b,0x2c,0xf7,0x3e,0x68,0xb4,0xf4,0x06,0x3b,0x44,0x5c,0x77,0x55,0xaa,0xf2, +0x92,0xc4,0x96,0x30,0xb6,0x72,0xb6,0x26,0x80,0xae,0x14,0xa9,0x85,0x01,0x57,0x07,0xe1,0x3a,0xf3,0x1a, +0xa0,0xd2,0xd8,0x26,0xb8,0x06,0x63,0xc9,0x1e,0x59,0x49,0xf6,0x7b,0x3d,0x7e,0x83,0x97,0xb2,0x6f,0xb6, +0xff,0xb5,0x14,0xd5,0x84,0xf5,0x99,0x03,0xb0,0xa3,0x09,0x70,0x1d,0x25,0x3e,0xe8,0xc2,0x5e,0x25,0x5e, +0x17,0x36,0x78,0x66,0x01,0x9e,0x38,0x16,0xa0,0x32,0x85,0xb3,0x61,0x45,0x86,0x01,0x8e,0x12,0xb4,0x0e, +0x59,0x11,0x58,0xe0,0x68,0xaa,0x60,0x40,0xce,0xa2,0xce,0xa9,0x94,0x80,0x19,0x90,0xd2,0xd6,0xc0,0x80, +0x16,0x8a,0xfd,0x16,0xa8,0x6e,0x44,0x50,0x7b,0xad,0xae,0xac,0x07,0xd4,0x2c,0x6e,0x39,0x8a,0x68,0x2d, +0x74,0x28,0x8c,0xba,0xbb,0x11,0xcc,0x31,0xe0,0xa5,0x59,0x49,0x87,0xbd,0xf6,0xd9,0xa5,0xd8,0x7a,0xca, +0x5d,0x42,0x1a,0xef,0xd4,0x28,0x4a,0xc9,0xee,0x32,0xc2,0x08,0xc5,0x2e,0xa3,0x5b,0xcb,0xf0,0xbc,0xd5, +0x0c,0x6c,0xf4,0x47,0x51,0xdd,0xec,0xca,0x9a,0x43,0x7c,0x92,0xd6,0xe6,0x0e,0x25,0x1b,0xa0,0xc0,0xed, +0xc1,0x32,0x35,0x21,0x4d,0x7e,0xcf,0x55,0x73,0x87,0xad,0x80,0xcc,0x62,0x75,0xff,0x92,0xd6,0xe8,0x59, +0x66,0xfe,0x9a,0xad,0x50,0x6d,0xa0,0x35,0xd0,0x2e,0x77,0xb7,0xee,0x0c,0xa5,0xb2,0x2f,0x43,0xad,0x79, +0xab,0x02,0xe9,0xc2,0xa4,0x72,0x7e,0xc1,0x3a,0xed,0xe6,0xaa,0x04,0x76,0xd8,0xad,0xbb,0x6c,0x9a,0x69, +0x0b,0x1d,0x61,0xfd,0x32,0xa6,0xa9,0x0b,0xd7,0x6a,0x64,0x25,0xdb,0x06,0x15,0x53,0x75,0xb3,0xed,0x5f, +0x07,0xda,0xbd,0xb7,0x56,0x09,0xbd,0x4c,0xdf,0x54,0xc7,0x76,0xad,0x8e,0x89,0x0a,0xcc,0xa8,0xcf,0x14, +0xf9,0x96,0x5a,0x71,0x65,0x2b,0x60,0xa5,0x17,0x1a,0x1d,0xd8,0x43,0x7a,0x0e,0x90,0xc1,0xb5,0x5d,0x58, +0x48,0x8e,0x68,0x63,0xc3,0x79,0x80,0x3a,0x1c,0x7a,0xd6,0x46,0x32,0x48,0xc8,0x95,0xf8,0xd1,0x31,0xcb, +0x0c,0x87,0x1c,0xae,0xfa,0x41,0x57,0x98,0x9a,0xd1,0x53,0x5b,0x1a,0x5d,0x24,0xd3,0x08,0xd6,0x05,0x45, +0x8e,0xdb,0x85,0x29,0x5a,0x92,0x2c,0x84,0x3d,0x88,0x76,0x97,0x11,0xc5,0xdf,0xad,0xb1,0x30,0x89,0xb2, +0x2d,0x0a,0xad,0x28,0xe6,0x41,0x12,0x6e,0xb5,0x4e,0x67,0x79,0x06,0x93,0xe2,0x68,0xed,0xd3,0xd6,0x71, +0xeb,0xe8,0xd3,0x65,0xf7,0xb8,0xed,0x6f,0xc9,0xd0,0x1a,0xdf,0xbe,0x6d,0xa1,0x31,0xd9,0xe7,0xa4,0x5c, +0x01,0x90,0xa1,0x03,0x46,0xbf,0x35,0x1a,0x74,0x37,0xe5,0x3b,0xe2,0xa8,0x19,0xfa,0xbc,0x48,0x62,0x7f, +0xcd,0x91,0xa5,0x85,0xcb,0x40,0x37,0x15,0x40,0x5a,0x12,0xb2,0x3e,0xed,0x6d,0x6c,0x40,0xa9,0xec,0xb7, +0x64,0x3e,0x17,0xad,0x8c,0xd6,0xf2,0x8b,0x81,0xac,0xc1,0x1f,0x69,0x75,0x00,0x27,0x71,0x25,0x48,0x36, +0xc0,0xc8,0x1f,0x2c,0x2b,0x62,0xa4,0x20,0x61,0x1b,0x13,0x7a,0xde,0x35,0xaa,0x7b,0x98,0x54,0x43,0x51, +0x88,0x48,0x11,0xe5,0x91,0x03,0x49,0x34,0xfa,0x9b,0xb9,0x47,0x2a,0x8b,0x42,0x22,0x99,0x99,0x5d,0xd1, +0x62,0x98,0x74,0xd5,0xc3,0xaa,0x05,0xc1,0x44,0xad,0x55,0xdb,0x2d,0xa2,0xb3,0x28,0x4f,0xa0,0x4a,0x0a, +0x09,0xa2,0x7b,0x36,0x97,0x3c,0x5a,0xdc,0x4a,0x94,0x09,0x5e,0x50,0x04,0x11,0x5b,0x87,0x62,0x4c,0x08, +0xb8,0xaf,0x91,0x17,0xe8,0x07,0x5a,0xc0,0x02,0xe5,0xe5,0x1b,0x39,0x8b,0xea,0x1e,0x5e,0xf8,0x90,0x49, +0x36,0x55,0xef,0x2f,0x53,0x0c,0xb2,0x13,0xe7,0xe5,0x57,0xe6,0x42,0x30,0x06,0x26,0xc9,0x5a,0x0b,0x14, +0x7b,0x90,0x6f,0xfb,0xf4,0x18,0x45,0xbe,0xaa,0x1d,0x62,0x84,0x39,0x8c,0x25,0xfe,0x7a,0x47,0x21,0x0c, +0x29,0xaa,0x27,0xa5,0x61,0xdc,0xcc,0x3d,0x71,0xdb,0x45,0x96,0xf4,0x79,0x72,0x81,0x4c,0x0a,0xe5,0x01, +0x97,0x00,0x8c,0x15,0xbb,0xc3,0x94,0x69,0x93,0xa4,0x40,0xef,0x0b,0x28,0xbf,0x3f,0xa0,0x65,0x47,0x1d, +0xe6,0x3c,0x87,0x86,0x38,0xac,0x27,0xc5,0x36,0xd1,0xc2,0xa3,0x88,0xe3,0x0e,0x40,0x47,0x68,0x23,0xaa, +0x53,0xd7,0x91,0xde,0xd8,0x60,0xdf,0xc6,0x24,0x41,0x81,0xde,0xe3,0x89,0x03,0x99,0x78,0x77,0xc3,0x6c, +0x4f,0xa0,0x61,0x69,0x5a,0x37,0x96,0x3a,0x95,0x10,0xb2,0x20,0x32,0x6e,0x70,0x7b,0xf9,0xa0,0x3c,0x8e, +0xe3,0x88,0x54,0x58,0x27,0xc5,0x73,0xee,0xfc,0xa4,0x09,0x59,0xa2,0x77,0x52,0xb4,0xbc,0x81,0x20,0xd3, +0xc4,0xb3,0xea,0x70,0x91,0x7b,0x65,0x6d,0x58,0x80,0x23,0xb6,0xac,0x9d,0xa2,0x41,0x1d,0xc9,0x49,0x89, +0xd8,0x12,0x7b,0xb2,0xb3,0x6b,0x7b,0x0f,0xd7,0xb6,0x76,0x64,0x47,0x54,0x5e,0x58,0x55,0xb4,0x50,0xf1, +0x08,0x84,0x7f,0x68,0x52,0x29,0x47,0x59,0xca,0x53,0xd2,0x52,0xb2,0xaa,0xa7,0xb4,0xf7,0x67,0x67,0xb2, +0xf6,0x9d,0x4f,0xe9,0xda,0xda,0x53,0x94,0x27,0xed,0x08,0x08,0x53,0x37,0xbd,0xed,0xc1,0xb6,0x89,0xb9, +0x9f,0xd2,0xa7,0x5b,0x54,0xb8,0x8a,0x30,0x73,0x98,0xb5,0x4c,0xb4,0x2a,0x24,0x0e,0xa0,0x48,0x68,0x60, +0x54,0x69,0xa4,0xb0,0xca,0x89,0x84,0x4d,0x6f,0x83,0x6f,0xda,0x8c,0xee,0xef,0x46,0x36,0x7d,0x46,0x2e, +0xd9,0x09,0x03,0x6d,0x38,0x92,0x0f,0x28,0x28,0xa5,0x31,0x65,0x80,0xf7,0xe9,0xc3,0xa7,0x5b,0x46,0x84, +0x9d,0x15,0xfd,0xbf,0x6d,0x9d,0x67,0x67,0xb7,0xae,0x34,0xd5,0x68,0x9a,0xae,0x22,0x29,0xaf,0x1a,0xbb, +0x6d,0x41,0x2e,0xce,0x54,0xe4,0xbc,0x65,0xe3,0xa2,0x14,0xb1,0xba,0xab,0x2b,0x26,0x90,0x9b,0xaa,0x67, +0x58,0xa3,0xee,0x7d,0xe4,0x32,0x56,0x56,0x4d,0x10,0xb7,0xad,0x79,0xbd,0x67,0xae,0x4f,0xd7,0xf6,0xa6, +0xaf,0x4f,0x74,0x60,0xab,0xb6,0x7f,0x3a,0x1c,0x15,0xe7,0x78,0xa4,0x55,0x6c,0x2e,0x32,0x63,0x06,0x5b, +0x2b,0xf4,0x58,0xca,0x9f,0x96,0x29,0xb3,0x31,0xd8,0x3c,0xf0,0x34,0x1c,0xa1,0x5c,0x47,0xed,0x04,0xfd, +0x76,0xc8,0xfd,0x52,0x8f,0x68,0x55,0x85,0x13,0x67,0x3f,0x7a,0x74,0x67,0x06,0x96,0x7c,0x19,0xcd,0x47, +0xb1,0xf8,0x21,0xc3,0xb2,0xd9,0x7b,0x9a,0xbd,0x2b,0xd6,0xf9,0x11,0xf2,0x5b,0x8f,0x27,0x97,0x34,0x0b, +0x33,0xa7,0x16,0x2b,0x4c,0x89,0x69,0x55,0x70,0x9e,0x81,0x29,0x3e,0x3e,0x73,0x28,0x06,0xc8,0x6f,0x6b, +0x0f,0x7c,0xfc,0x8e,0x2a,0xc2,0x30,0x74,0x44,0x94,0x21,0x7c,0xf4,0xb3,0x37,0x04,0xa3,0x89,0xd2,0xd5, +0x44,0x5a,0x35,0x51,0x6a,0x4d,0xa4,0x66,0x13,0x39,0xab,0x4e,0x52,0x1b,0xda,0xe6,0xcf,0xde,0x9a,0x92, +0xb0,0xd8,0x29,0x47,0xc5,0xa0,0x0c,0x92,0xb6,0xab,0x09,0x7d,0x70,0x65,0x63,0xfa,0xac,0x7b,0x4b,0x81, +0x1b,0xac,0xc1,0xa5,0xf6,0xaf,0x08,0x7a,0x90,0x5c,0xa3,0xd8,0xb7,0x6a,0xa6,0xb6,0x18,0x0c,0xe0,0xf6, +0xa3,0x6b,0x63,0xda,0x9b,0x99,0x3f,0xa2,0x9e,0xb6,0x39,0x8e,0xe9,0xdb,0x0c,0xf8,0xcc,0xe7,0xd9,0xa5, +0x36,0x35,0x12,0x19,0x47,0x1d,0x5f,0xbe,0x01,0x38,0xc6,0x93,0xfc,0x39,0x73,0x18,0x78,0x8d,0xe1,0x43, +0x4f,0x9d,0x6a,0x2d,0xe5,0x5c,0xb6,0x0c,0x45,0x0c,0x9e,0x6f,0xdf,0x92,0xae,0x94,0x44,0x13,0x1f,0x20, +0xee,0x36,0xb0,0x8e,0x96,0xb0,0xa1,0x8a,0xb8,0xe9,0x00,0x88,0xa1,0x43,0x99,0x89,0x9e,0x7f,0xdd,0x43, +0x9e,0x1f,0x08,0x1e,0xea,0x34,0x83,0xa5,0x95,0x47,0x53,0x0a,0xf2,0x25,0xcf,0xd7,0xb0,0x84,0x54,0xce, +0xc6,0xb8,0x2c,0xec,0xc6,0x57,0x13,0xcc,0x58,0xbd,0xf7,0xaa,0x29,0xf2,0xed,0x5b,0xcf,0xee,0xfe,0x73, +0xa8,0xfd,0x6d,0x76,0xa1,0x4d,0x60,0x9d,0xf1,0x1a,0x72,0x4c,0xd2,0x1a,0x86,0xa1,0x8e,0xa3,0xec,0x7d, +0x11,0xb6,0xca,0x76,0x1d,0xb3,0x8e,0xa3,0x0b,0xfe,0x16,0x73,0x1c,0x38,0xb3,0x0e,0x92,0x49,0x1c,0x14, +0xc8,0x00,0xb7,0x8a,0x10,0xa6,0x58,0xb1,0xd3,0xa7,0x9f,0x7d,0x9c,0xd1,0xc5,0xa6,0x05,0x58,0x1b,0x5b, +0x8a,0xb7,0x93,0x5e,0x9b,0xc7,0x9d,0x3e,0xec,0xa9,0xb1,0xc9,0x45,0x93,0x64,0x59,0x5c,0x9b,0x07,0x29, +0x43,0x73,0x08,0x11,0xda,0x05,0x07,0x1d,0xad,0x42,0x1b,0x82,0x62,0xe1,0x74,0x5a,0xfd,0x4e,0xe1,0x5b, +0xc8,0x5d,0xd7,0x26,0x17,0x52,0xf7,0x85,0xee,0xa7,0xaf,0x22,0xee,0xad,0x48,0x8b,0x1e,0x8c,0x9b,0x26, +0x1b,0x93,0x15,0x10,0x9a,0x62,0xd4,0xbc,0xd6,0xed,0xe8,0xac,0xf1,0x35,0xe6,0xd3,0x65,0xba,0x13,0x76, +0x1f,0xab,0x2b,0xb8,0x2f,0xe3,0xdb,0x3b,0x20,0xd7,0x9b,0x72,0xfc,0xaa,0xb8,0x73,0x5a,0x73,0x14,0x59, +0x85,0xb5,0x88,0x60,0x5d,0x8f,0x72,0x21,0xe8,0xce,0x57,0x52,0xc9,0x85,0x8a,0xcf,0x96,0x6a,0xbc,0xb1, +0x2b,0xbe,0xe2,0xb8,0x27,0xa2,0x8c,0x35,0x2c,0xe2,0x55,0xb6,0x89,0x7d,0x6c,0x2c,0xa7,0x32,0x6a,0x0a, +0xfd,0x7a,0xf8,0x58,0x63,0xac,0x46,0xd6,0x71,0x8f,0x7e,0xdb,0xd8,0xbf,0x83,0x7e,0x29,0xe0,0x24,0xe1, +0x30,0xd0,0x2a,0xc0,0xa6,0xcf,0xcd,0x65,0xe2,0xb0,0x91,0x0e,0x23,0x73,0xec,0xdb,0xdb,0x83,0x9e,0xb1, +0x7c,0x44,0xa0,0x3e,0xb1,0x84,0x30,0x54,0x07,0xd5,0x2f,0x02,0x5a,0x58,0x0b,0x4a,0x01,0xf3,0xa2,0x8a, +0x1d,0x8b,0xca,0x5d,0x5e,0x2c,0x31,0x55,0xde,0x58,0x66,0x8d,0x8d,0xba,0xca,0xd0,0xc2,0x8b,0x3b,0xd6, +0x9a,0xb3,0x2a,0xb0,0xc6,0x4c,0xbf,0x8a,0xd5,0x86,0x0d,0xc5,0x11,0x6a,0xe8,0x38,0x9e,0x65,0xec,0x94, +0x95,0x03,0x42,0xaf,0x28,0x76,0x34,0xee,0x94,0x32,0x5a,0x63,0x15,0xf1,0x89,0x0c,0x2b,0xaa,0x68,0x47, +0x8e,0x72,0xbf,0x2c,0x1c,0xa5,0x0c,0xc1,0x0c,0x47,0xca,0x69,0x79,0xe7,0x78,0x1c,0xe1,0x90,0xaf,0x95, +0x78,0x54,0xe0,0x2f,0xa1,0xf8,0xdd,0x00,0xbb,0x5c,0x30,0x24,0xa9,0xca,0x63,0x30,0xaa,0x6a,0x3e,0xd4, +0xe5,0x69,0x0a,0x31,0xb1,0x06,0x5a,0x32,0xaa,0xa4,0x36,0xe3,0xb4,0xba,0xd1,0x39,0x14,0xd7,0x5e,0x70, +0x94,0xc9,0x86,0x4e,0xaa,0x33,0xf4,0xa6,0x5e,0xde,0xbe,0x8f,0x2b,0x7a,0x68,0x5f,0x2f,0xcd,0xdb,0xa7, +0x63,0x94,0x69,0xab,0x6d,0x64,0x4e,0x54,0xcf,0x35,0x66,0xc8,0xbc,0x58,0x55,0x67,0x89,0x98,0x7d,0xaa, +0x08,0xcf,0xfc,0xce,0xa3,0x6b,0xfb,0x66,0xa2,0x9d,0x4d,0x31,0x65,0x27,0xa1,0xab,0x64,0xbb,0x1f,0x98, +0x6c,0xf1,0xc6,0xc6,0x03,0x5b,0xbe,0xf2,0xf4,0x47,0xd4,0xa1,0xed,0x84,0x3f,0xc8,0x6b,0xba,0x9c,0xfa, +0xa1,0xc0,0xe6,0x66,0x86,0xab,0x93,0x68,0xb3,0x82,0xee,0xd9,0xd5,0x26,0x51,0xe3,0x17,0x18,0x6b,0xfb, +0x64,0x6b,0x3c,0x5e,0xad,0x4d,0xe6,0x1e,0x67,0xad,0xdd,0x94,0xdc,0x04,0x1d,0x8d,0xf5,0x6e,0x3a,0x96, +0x6b,0x75,0x05,0xcd,0xcc,0xda,0xed,0x77,0x66,0xfb,0x58,0xaf,0x36,0x03,0x37,0xd3,0x58,0x3f,0xb4,0xd1, +0x75,0x67,0xed,0x44,0x54,0xfa,0xee,0x75,0x1e,0xf3,0x1e,0x9c,0xe4,0x7a,0x75,0xb4,0x6e,0x6c,0x90,0x0b, +0xea,0x68,0x5c,0xb4,0x1c,0x4c,0x41,0xa7,0xf4,0x77,0xb8,0x93,0x90,0x73,0x38,0xc3,0x7d,0x20,0x9b,0x4f, +0x28,0x76,0x93,0x3a,0x9b,0x31,0x92,0xa1,0x20,0xb4,0xe4,0x10,0x89,0x77,0x71,0x53,0xe2,0x97,0x85,0x9b, +0x0e,0xff,0xf2,0x3e,0x6b,0x28,0xbe,0x40,0x27,0x14,0xa8,0xbf,0xb5,0xde,0xd7,0x05,0x82,0xe1,0x95,0x3c, +0x1a,0x28,0x4c,0xfd,0xed,0x5c,0x05,0xd4,0x3c,0x0c,0x38,0x9c,0x10,0x18,0x33,0x64,0xe0,0x69,0xa2,0x07, +0x39,0xea,0x5e,0x60,0xca,0x9a,0x0c,0x20,0x55,0x97,0x17,0xe8,0x22,0x18,0x03,0xe6,0x27,0xce,0x90,0x10, +0x42,0xa8,0xe4,0x00,0x39,0x3b,0x43,0x21,0xbe,0x12,0x3c,0x18,0x10,0xdc,0x09,0x95,0x5f,0xc9,0x0f,0x1c, +0x50,0x9c,0x2b,0x61,0x2b,0x81,0x80,0x03,0x74,0x9f,0x63,0x06,0x1a,0x53,0x68,0xf0,0x38,0xd0,0x2f,0x75, +0x83,0xbe,0xfc,0xe6,0x9d,0x60,0xf0,0x28,0xb0,0xb6,0x3f,0x28,0x20,0x65,0xab,0xd0,0x44,0xa5,0x39,0x87, +0x2f,0x5e,0xc2,0x0f,0x84,0xae,0x2f,0x00,0xe3,0x8a,0x71,0xc1,0x1f,0xe8,0x4a,0x76,0xbc,0xad,0x26,0xef, +0x0f,0xa4,0x74,0x30,0x8c,0x03,0xba,0xc8,0xeb,0x30,0xd6,0x91,0x80,0x77,0x73,0xb8,0x99,0x07,0xb3,0x20, +0x0b,0xf2,0x60,0x1e,0x4c,0x82,0xd3,0x60,0x19,0x2c,0x84,0xd9,0x63,0xff,0x69,0x3d,0x58,0x5c,0xca,0x52, +0xe3,0x2a,0x2e,0x74,0xcf,0x1f,0x1c,0xa1,0x97,0x26,0x96,0x1c,0xb4,0x26,0xf2,0xc7,0x69,0x98,0x60,0xdc, +0xd4,0xd1,0xa9,0x12,0x1a,0x8b,0x88,0x7a,0xfe,0x68,0x32,0xa8,0x66,0x65,0x25,0x52,0x5e,0xaa,0xd7,0xad, +0x12,0x0d,0x43,0x06,0x4a,0x83,0x0a,0xed,0x50,0x7a,0xc1,0x3c,0x5c,0x4a,0x15,0xb7,0xfc,0xe9,0x7c,0x98, +0xb7,0xdb,0x7e,0x19,0x2e,0xd1,0x43,0x54,0xc4,0x56,0x67,0x24,0xa5,0x2e,0x64,0x2c,0xde,0x68,0xd4,0x9a, +0x11,0x06,0x41,0x16,0x6e,0x3f,0x85,0xf5,0x64,0xe2,0x9f,0x04,0x7d,0xc2,0x5b,0x20,0xbb,0x08,0xa3,0xa3, +0xd9,0x31,0xec,0x4d,0x92,0x3b,0x89,0x82,0x0c,0x9d,0x5c,0xc6,0x97,0x6b,0x18,0x36,0x80,0x7a,0xa2,0xb3, +0xb6,0xd7,0x82,0xb2,0x1a,0xb1,0x1b,0x9f,0x61,0xf8,0x69,0x87,0x22,0xc2,0x85,0x57,0x74,0xfe,0x19,0x02, +0xfb,0xe0,0xca,0x5c,0x62,0xfd,0xda,0x7a,0x12,0x8d,0xac,0x58,0x4c,0x02,0xa2,0x79,0x25,0x09,0x80,0xc6, +0x65,0x64,0xe4,0xd7,0xd7,0x90,0xc8,0x5e,0xb5,0x80,0x0c,0x90,0x15,0xab,0xc7,0x80,0x93,0x4b,0xa7,0x9a, +0xf9,0x15,0x41,0x3d,0x79,0xc0,0xe9,0x7a,0xa4,0x09,0xa9,0xcf,0x28,0xed,0x89,0xfa,0x43,0xdb,0xba,0xe9, +0xf2,0x19,0xc6,0xc8,0x36,0x39,0xb2,0x97,0x00,0x4b,0xb8,0x87,0x8e,0x80,0xca,0x3b,0x3d,0x9f,0x6d,0x01, +0xf0,0x95,0x6e,0x96,0x9c,0xc1,0x52,0x09,0x13,0x39,0x3f,0x2a,0xae,0x2e,0x0a,0x3d,0xf6,0xb6,0x58,0xdd, +0xdb,0x8a,0x51,0x41,0x5e,0xe4,0xc9,0x83,0x7c,0xb7,0xcc,0x7e,0xc1,0x08,0x38,0xfc,0x06,0xd7,0x2e,0x84, +0x95,0x00,0xcc,0xbf,0x62,0x48,0x9a,0x8b,0x6c,0x3d,0x20,0xc3,0x4d,0x8a,0x1f,0xd2,0x1c,0x4b,0xb6,0x33, +0x5c,0xa5,0xad,0x22,0xdc,0xa5,0x09,0x9d,0x15,0x5a,0x08,0xde,0xaf,0x3f,0x7f,0xdc,0xfb,0x00,0x2c,0xa1, +0x08,0x2c,0x46,0x6a,0x28,0x32,0x08,0x66,0xf2,0xed,0x1b,0xcf,0xca,0x44,0x2a,0xb3,0x60,0xf0,0x6f,0x3b, +0xbc,0x7c,0x81,0x21,0x21,0xc2,0x02,0x67,0x2c,0x2e,0x84,0xb2,0xab,0x1b,0x6e,0xd1,0x1d,0x01,0x6e,0x29, +0x2b,0x1b,0x45,0x1e,0x55,0x6b,0x36,0x2c,0xbe,0x7d,0xab,0xb7,0xe2,0x33,0x15,0xc8,0xc2,0xa0,0x76,0x03, +0x4e,0x8e,0x8a,0x63,0x69,0x03,0x81,0xbf,0x05,0xf9,0x31,0x60,0x2a,0x76,0x08,0x63,0x7e,0x24,0xf2,0x20, +0xcd,0xc3,0x39,0x1e,0x79,0x2b,0x6b,0xf3,0x28,0x3e,0x68,0x74,0xbc,0xb1,0x91,0x55,0xa3,0xac,0xea,0x97, +0xb9,0xbf,0xbb,0x95,0x29,0xd7,0xa3,0xd5,0x3c,0xbd,0x73,0xcd,0x4c,0x35,0x04,0x10,0x32,0xd6,0x02,0xfa, +0x6f,0xe0,0xad,0x67,0x90,0x6d,0xde,0x90,0x75,0x9c,0x1b,0xca,0x56,0xed,0xe8,0xa9,0x18,0x20,0x29,0x66, +0x55,0xe7,0x96,0xf7,0x96,0xf4,0xf5,0x84,0x19,0xf8,0x1a,0x6a,0x0f,0xa0,0x65,0x43,0xd1,0xf6,0x2a,0xff, +0xfb,0xf1,0x97,0xa4,0x28,0xd1,0x35,0xaa,0x78,0xc9,0xb4,0xd7,0x97,0x47,0x91,0x42,0xf3,0xeb,0xa1,0x34, +0x4b,0x75,0xac,0xc1,0x61,0xa9,0x71,0x25,0xe8,0x7b,0x3a,0xa2,0xe0,0xbb,0x5f,0xbc,0x00,0x59,0xa1,0x24, +0xbe,0xc4,0x6d,0x70,0x9e,0x5c,0x10,0xc7,0x81,0x8f,0xdf,0xf4,0x96,0x8f,0x1f,0xd2,0x2d,0x35,0xfe,0xc6, +0xf8,0xf0,0x2c,0x73,0x96,0x5f,0x2f,0xb9,0x2a,0xf8,0x42,0xa5,0xad,0x38,0xbf,0x88,0x3f,0x62,0xcb,0x14, +0x29,0x28,0x00,0x0e,0x59,0x6c,0x42,0xb8,0xff,0xa1,0x29,0xe9,0xc0,0x5b,0x64,0x0b,0xf4,0xea,0x80,0xd7, +0xeb,0xe7,0x3a,0x73,0xf4,0xcf,0x25,0xb4,0x53,0x7e,0x1d,0xf4,0x03,0xe9,0x10,0x82,0xaa,0xc8,0x45,0xd0, +0xee,0xc1,0x76,0x70,0x9e,0x8d,0x13,0xe6,0x88,0xf8,0x17,0x87,0x0c,0xc6,0xd8,0x67,0x68,0x46,0xf7,0xb7, +0xf8,0x2b,0xf9,0x81,0xc6,0x7e,0xa0,0x9e,0xf4,0x7b,0x26,0x37,0x82,0x17,0x69,0xb4,0xa0,0xd0,0x00,0xf0, +0xf7,0x30,0x9b,0xc7,0x39,0xae,0x94,0x41,0xb7,0xf7,0x18,0xee,0xab,0xdd,0x67,0xbf,0xbc,0x3a,0xd9,0x7f, +0xf1,0xd3,0xee,0xe1,0x9b,0xbf,0xbf,0x38,0xf9,0xb0,0xfb,0xea,0xc5,0xc9,0xfb,0xfd,0x37,0xaf,0xde,0xbc, +0x43,0xa5,0xb6,0xb2,0x2b,0x7e,0xf3,0xb5,0xa4,0x17,0x50,0xf0,0x71,0x2c,0x45,0xf6,0x95,0x87,0xd9,0x41, +0x99,0xeb,0x42,0xfd,0x52,0xee,0x6f,0x9e,0x37,0x64,0xf5,0x0c,0xd4,0x5d,0xc3,0x38,0x5c,0xe4,0x4c,0x65, +0x00,0x19,0xdf,0x79,0x43,0xfa,0x46,0xd2,0x0f,0x78,0x13,0xd1,0x82,0xb7,0x6c,0x3f,0x7e,0xbc,0x19,0x77, +0x73,0xdc,0xc0,0x54,0xec,0x15,0x7f,0xd8,0x0f,0xd5,0x61,0x8a,0xb7,0x31,0x0c,0x4f,0xd7,0x4e,0x58,0xc3, +0xb8,0xa8,0x97,0x9e,0xd6,0x4b,0x6b,0x91,0x8d,0x0b,0x2a,0x5d,0xf8,0xc2,0xc7,0x71,0xad,0xf4,0xb8,0x5e, +0x3a,0xaa,0x4a,0x47,0x54,0x1a,0x1d,0xe9,0xb4,0xc3,0x04,0x26,0x69,0x34,0x1c,0xe7,0x71,0xf4,0x79,0x28, +0xbb,0x18,0xd9,0x7d,0x8c,0xfe,0x83,0x3b,0x29,0xce,0x83,0x5a,0xe9,0xa8,0x5e,0x3a,0xab,0x4a,0x67,0x54, +0x3a,0xab,0x48,0xd4,0xce,0x74,0x22,0xa1,0xb9,0x31,0xd2,0x08,0xfe,0xb6,0xbc,0xb6,0x83,0x2a,0xe4,0x89, +0xc4,0xd1,0x5f,0x77,0xfa,0x18,0xd2,0x7d,0xcf,0x6a,0xe0,0x7b,0xad,0x05,0x76,0x65,0x92,0xb7,0xbd,0xef, +0x03,0xf9,0x31,0xd5,0x3f,0xc6,0xf0,0x51,0xab,0x20,0x92,0x15,0x44,0x7f,0x14,0x8e,0x01,0x99,0xc1,0x3b, +0x70,0x8d,0xbe,0xd7,0xdb,0xba,0x0d,0xb6,0xea,0x23,0xaa,0xa1,0x8e,0x86,0xd6,0x58,0x1b,0xfc,0x85,0xca, +0x84,0xdf,0x17,0xd1,0x78,0x21,0xfe,0x5e,0xd8,0x48,0x00,0xf0,0xf7,0x5a,0x29,0xae,0x7b,0xa6,0x37,0x54, +0xe8,0x1f,0x17,0xae,0x56,0x23,0x59,0x41,0xb4,0xaa,0x5d,0x37,0x11,0xb0,0xd4,0xf7,0x7a,0xf9,0xdb,0x60, +0xb0,0x92,0x08,0x63,0x51,0x1b,0x8e,0xff,0xad,0x08,0x30,0xfe,0x5e,0x2b,0x71,0x1f,0x02,0x8c,0x25,0x01, +0x68,0x14,0xef,0xd4,0xf9,0xb1,0xea,0xfc,0xf8,0x9e,0x9d,0x97,0xca,0x2a,0x39,0x6e,0xcc,0xc0,0x17,0x1e, +0x66,0x74,0xee,0xd5,0x15,0xcd,0xe1,0xbe,0x95,0x84,0x57,0xd1,0xa0,0x7f,0x4d,0x41,0x0d,0xe9,0x1e,0x12, +0x77,0x29,0x8e,0x71,0x6b,0xeb,0xff,0x7c,0x77,0xd4,0xeb,0xfc,0x35,0xea,0x9c,0x1d,0x5f,0xfd,0x70,0xfd, +0x60,0x2b,0x21,0x75,0xa9,0x7a,0xde,0x23,0xca,0xa3,0x37,0xe5,0xa4,0x78,0x17,0xbd,0x6b,0x25,0xdd,0x3c, +0xec,0xff,0xb8,0xa9,0x79,0xea,0xe6,0x98,0xa6,0xad,0x3e,0xdc,0x77,0x02,0xd8,0x1f,0xb6,0x30,0xea,0x59, +0xe5,0xdd,0x5d,0x2b,0x38,0x75,0x17,0xdc,0xbe,0xb1,0xe0,0xd8,0x5d,0xf0,0x87,0xc6,0x82,0x8f,0xd1,0xfc, +0x40,0x6e,0x51,0xb2,0x96,0xc8,0x5d,0xcb,0x23,0x67,0x2d,0x8a,0x47,0xb2,0xc9,0x56,0xa3,0x5a,0x23,0xc0, +0xed,0x49,0xd7,0xbb,0x2f,0xe9,0x6e,0xa6,0x79,0x03,0xe9,0x9a,0x69,0xfe,0xe8,0x0e,0xa4,0x73,0x0f,0x40, +0x23,0xe9,0xaa,0x59,0xf5,0xa4,0x81,0x76,0x15,0xc4,0x5f,0x5c,0xc4,0x73,0x11,0x60,0xfb,0x46,0xca,0xb9, +0xf0,0xbe,0xa9,0xd4,0xd8,0x51,0xea,0x71,0x63,0xa9,0xbf,0xba,0x69,0x56,0xaf,0xe2,0x47,0x67,0x15,0x37, +0xcf,0xb5,0x26,0x7a,0xdd,0x95,0x5c,0xbd,0x7b,0x91,0x6b,0xfb,0x5e,0xe4,0x7a,0xd4,0x58,0xea,0x2f,0xb7, +0x25,0xd7,0x93,0xbb,0x91,0x0b,0x0f,0xd5,0x4f,0x05,0x86,0xb8,0x2d,0x36,0x5b,0x48,0x9a,0x4f,0xdd,0xe3, +0xf6,0xf7,0xdf,0x8e,0x7a,0xfd,0xe3,0xd1,0xa7,0xee,0x08,0x53,0x8e,0x37,0x7d,0xc8,0x0c,0xfe,0xf5,0x00, +0x9f,0x7c,0xf7,0x88,0x01,0x8e,0x7f,0x12,0x8a,0x8c,0x01,0x4d,0x89,0x3c,0xb4,0xd0,0x88,0x20,0x87,0x22, +0x05,0x54,0xf1,0xa8,0x35,0x5d,0xd9,0x96,0xe7,0xb7,0xfb,0x81,0x96,0x10,0xe0,0x3b,0xaf,0xf7,0x3d,0xde, +0x3f,0xa5,0xd0,0x41,0xf9,0x26,0xe8,0x3b,0x67,0xdd,0xcb,0x79,0x16,0x01,0x90,0x8f,0x0e,0x5b,0x1c,0x23, +0xe7,0x98,0xa3,0xa5,0x63,0xa2,0x34,0x62,0x18,0xd4,0x31,0x0c,0xec,0xec,0x5b,0xa3,0x3c,0xbd,0x13,0xca, +0xd3,0x9b,0x50,0xce,0x47,0x8d,0x48,0xd7,0x71,0xa4,0x5e,0x60,0xf8,0xe1,0x37,0x3a,0xad,0x07,0x66,0x0d, +0x76,0x7e,0xbd,0x90,0x7f,0xfb,0x01,0x1a,0xdf,0xa9,0xb7,0xe3,0xd5,0xbd,0xcd,0x7d,0xc7,0x28,0xfd,0xa1, +0xe8,0x46,0x77,0x42,0xd7,0x82,0xb6,0x20,0xaf,0xc4,0x9e,0x11,0x6a,0xeb,0x11,0x79,0xd0,0x7f,0xaf,0x3d, +0x63,0x63,0xc3,0x81,0xe3,0x9f,0xba,0x67,0xb8,0x30,0xf8,0x77,0xdb,0x59,0x9d,0x38,0xfe,0xb9,0x3b,0xab, +0xb1,0x10,0xfe,0xbc,0x1d,0x76,0x76,0xa7,0x15,0x61,0x43,0xc3,0x65,0xed,0xff,0xc7,0x1e,0x5b,0xdc,0x09, +0xe9,0xa2,0x69,0x19,0xff,0x47,0xec,0xb0,0x17,0x77,0xea,0xeb,0xc5,0xaa,0xbe,0xfe,0xe7,0xec,0xaf,0xf2, +0xa5,0x19,0xef,0xa4,0xb0,0x5f,0x1d,0x66,0xfb,0xd3,0xb1,0x21,0x2a,0x0c,0x72,0xf5,0x88,0xf0,0x34,0xec, +0x6f,0x3d,0x81,0xeb,0xe6,0x4e,0xf8,0x78,0xeb,0xc9,0xa8,0x3f,0x88,0x9f,0xf6,0xb7,0x7e,0x18,0xf5,0x3b, +0x4f,0x36,0x5b,0x71,0x07,0xb2,0x60,0x74,0x76,0x1e,0x41,0x0e,0x7d,0x3f,0xc2,0x6f,0x74,0xa4,0x0a,0xe0, +0x90,0xb7,0xb1,0x01,0xc5,0xbb,0x8f,0x45,0x29,0x84,0x89,0xe1,0x17,0x42,0x8b,0xf2,0xdd,0xc7,0x08,0x1e, +0x21,0x78,0xf7,0x31,0x41,0x8b,0x46,0x76,0xb6,0xb9,0x34,0x14,0x26,0xc0,0x6d,0x6e,0xe8,0x71,0x55,0xf4, +0x31,0x37,0x95,0x85,0xad,0xa4,0xdd,0xea,0x77,0x12,0x7f,0x13,0xfe,0x0f,0xbd,0xdc,0xcc,0x83,0x34,0x6c, +0x15,0x6d,0x56,0x43,0x54,0x69,0xf3,0xb0,0x15,0x61,0x5a,0x54,0xa5,0x89,0x27,0x94,0xab,0x7c,0x90,0x05, +0xd3,0x41,0x1a,0x8c,0x07,0xf3,0x6b,0xa4,0x08,0x70,0x7d,0x87,0xd9,0xeb,0xe2,0xc2,0x4d,0x11,0x7a,0x1f, +0x15,0x82,0xb7,0xf3,0xe8,0x8b,0xc8,0x83,0x36,0x39,0x25,0x91,0xd0,0xd0,0x62,0xd6,0x49,0x55,0x20,0xac, +0xb0,0xb7,0x1e,0x66,0xa3,0xf9,0x56,0x06,0x38,0x27,0xe8,0x3e,0x64,0x3e,0xea,0x0d,0xe2,0x10,0xd2,0x5a, +0x4f,0xda,0xad,0xb2,0x93,0xfb,0x5b,0x73,0xff,0xfb,0x27,0x83,0x12,0x93,0xb6,0xdb,0xad,0xbc,0x13,0x43, +0xca,0x20,0xc7,0xcf,0x47,0x6d,0xe8,0x6f,0x89,0x9f,0x50,0x76,0x2b,0x7c,0x02,0x04,0xcb,0x82,0xab,0xd9, +0x00,0x70,0x19,0x14,0xc1,0xc5,0x20,0x22,0xb4,0x9d,0x6f,0x5a,0x39,0xea,0x72,0x0b,0x53,0x94,0xc5,0x12, +0x56,0xa3,0xd4,0x69,0x42,0x19,0x04,0x54,0x01,0x63,0x05,0xff,0x2e,0x06,0xfd,0x20,0x87,0x7f,0x53,0xf8, +0x37,0x86,0x7f,0x28,0x85,0x60,0xc0,0x42,0x0f,0xab,0xce,0x75,0xb0,0xcf,0x13,0xa9,0x04,0xc1,0x82,0x6c, +0x98,0xf4,0xe2,0x09,0x73,0xbd,0x17,0x5c,0x21,0x36,0x52,0x9e,0xef,0xab,0x7a,0x84,0xcc,0x1b,0x6d,0x94, +0xf8,0x34,0xd0,0x2b,0x10,0x2e,0x45,0xf0,0x89,0xc9,0x95,0x1c,0x7a,0x97,0x17,0x0b,0xaf,0x6d,0xe6,0xf1, +0x43,0x81,0x19,0x67,0x3d,0xec,0x8d,0xe0,0xef,0xc0,0x53,0xba,0x8e,0xa8,0x03,0x85,0xea,0x8a,0x06,0x7d, +0xba,0x97,0xc9,0x64,0x1a,0x97,0xac,0x67,0x69,0xe6,0x60,0xb4,0xbc,0x79,0xf4,0xd5,0x95,0x85,0x55,0x59, +0x9a,0xfb,0xfd,0xf5,0xb0,0x0e,0x83,0x66,0x55,0x6f,0xe0,0x2f,0x10,0xbe,0x31,0x0f,0x3d,0xa1,0xb2,0x34, +0x3e,0x6e,0x3d,0xd4,0x0c,0x0f,0xf8,0xc5,0xac,0x23,0xb0,0xf0,0xd6,0x0a,0x7a,0xa5,0x97,0xbe,0xc1,0x06, +0x6b,0xe8,0x63,0x63,0xe8,0x09,0x1b,0x84,0x87,0xfe,0x30,0x37,0xac,0xb8,0xbb,0xfc,0x8c,0xaa,0x7a,0x71, +0x42,0x19,0x7e,0x43,0x17,0x73,0x0c,0x79,0x88,0x91,0x39,0xe3,0x96,0x37,0xce,0x26,0x5a,0xc8,0x87,0xbc, +0xf2,0x7a,0xa6,0x17,0x04,0x70,0x7a,0x3f,0x41,0xcf,0x05,0xbf,0xe4,0xf3,0xd6,0x36,0x6c,0x3f,0x43,0x34, +0x96,0x8a,0xa3,0x49,0x55,0xf8,0xe1,0x53,0x42,0x7a,0x8d,0x9c,0x04,0x79,0xe8,0x27,0x78,0x0b,0xdf,0x17, +0x76,0xba,0xdc,0xb5,0x4b,0xaa,0x62,0xed,0x0a,0xed,0x8b,0xa7,0x24,0x89,0x1d,0xac,0x2d,0xa1,0xb2,0x87, +0xed,0xa4,0xed,0xf9,0xd0,0xc1,0x4e,0x1e,0x2f,0xe2,0xa8,0x5c,0x3b,0xa5,0x47,0x63,0xf1,0x67,0x78,0xfd, +0x74,0x8b,0xaa,0x45,0x8b,0x24,0x6c,0xb2,0x3c,0x9f,0x0b,0x83,0x50,0xa1,0x09,0x57,0x7f,0x78,0xd2,0xe8, +0x81,0xe0,0x27,0x02,0xd0,0x2e,0x2f,0x35,0xe8,0xee,0x5d,0x81,0x52,0xda,0xbb,0x65,0x0d,0x08,0xea,0x44, +0xe2,0x1e,0x75,0xb0,0x29,0x2a,0xd7,0xc1,0x7a,0x03,0x2b,0x2b,0x60,0xf0,0x13,0x86,0xf4,0xed,0x6d,0xa3, +0xcb,0x9e,0xfe,0x3e,0xf2,0xe2,0xa8,0xbd,0x8b,0xc7,0xa6,0x89,0x8c,0x1c,0x4e,0x82,0x7e,0xb8,0xe3,0xca, +0x42,0x4c,0x9a,0x73,0xde,0xf3,0x3c,0x94,0x16,0x35,0x64,0x5b,0xe5,0x82,0xdb,0x5b,0xe6,0x45,0x96,0x23, +0x18,0x59,0x58,0x09,0xe8,0x7a,0xa5,0xaf,0x97,0xf1,0x1a,0xff,0xe4,0x5d,0xa3,0x83,0x96,0x6e,0x8b,0x18, +0x4b,0x9e,0x46,0xe9,0x45,0x54,0xd4,0xe1,0x0f,0x08,0xd0,0x28,0xf5,0x70,0x8d,0x14,0xea,0xc2,0x87,0xfd, +0x87,0x6b,0xec,0x04,0x30,0x7c,0xf8,0xb8,0xf7,0x70,0x8d,0x7d,0xd9,0x3e,0x84,0x42,0x88,0x09,0x57,0xe8, +0xc4,0x19,0x20,0x18,0x63,0x59,0xed,0xe9,0x2d,0xf1,0x3f,0x80,0x49,0x7f,0x17,0xfc,0x01,0xfe,0xee,0xf8, +0x43,0x21,0xf1,0xb0,0x79,0x43,0x37,0x00,0xf0,0x7e,0xdd,0x80,0xf3,0xe2,0x4e,0xdd,0x00,0xf8,0xbb,0x77, +0x83,0x0e,0xa5,0x1b,0x7a,0x00,0x30,0xf7,0xeb,0xc1,0x7e,0x3c,0xb9,0x53,0x0f,0x00,0xfe,0xee,0x3d,0x80, +0x42,0x37,0xe0,0x0f,0x10,0xf7,0xc3,0xff,0x55,0x8e,0xa1,0xbc,0xef,0xd2,0x03,0x2a,0x71,0xf7,0x3e,0x50, +0xb1,0x1b,0x7a,0x41,0x30,0xf7,0xeb,0xc7,0xb3,0xf9,0x1d,0x57,0x34,0x16,0xb8,0x7b,0x2f,0x9e,0xdd,0x3c, +0x95,0x10,0xe4,0x7e,0x7d,0xd8,0x9d,0x2f,0x66,0xd1,0x9d,0x3a,0x41,0x25,0xee,0xde,0x0b,0x2a,0x76,0x43, +0x37,0x08,0xe6,0x7e,0xfd,0xf8,0xc0,0x8a,0x18,0x4d,0x48,0x8b,0xec,0x67,0xd9,0x17,0x17,0x9a,0xfd,0x6a, +0xfb,0x21,0x8b,0x44,0x58,0x5f,0x74,0xec,0xe8,0xe8,0x72,0xc3,0xc2,0xb6,0xb2,0x72,0x32,0x2d,0xdc,0xa7, +0xeb,0xe7,0x41,0xb0,0xd6,0x75,0xd1,0xb3,0x4a,0xe6,0x3e,0x59,0x60,0xde,0x0a,0xb3,0x48,0xb6,0x06,0xeb, +0x9c,0x67,0xbf,0x75,0x50,0xbb,0xa4,0x23,0xdd,0x3f,0xb0,0x4b,0x33,0x99,0xcd,0x36,0xfb,0x2b,0x20,0x6e, +0x2e,0x4b,0xc7,0x7c,0x07,0xf5,0xd5,0xd0,0x73,0xb9,0x84,0x09,0x04,0x17,0x97,0xa5,0xc8,0x2d,0xa1,0xe7, +0x1d,0xc7,0x21,0x5e,0xb3,0x55,0x20,0x9f,0x21,0x79,0xc5,0x81,0xa0,0x49,0x82,0xa3,0x9c,0x49,0x3b,0x83, +0x19,0xc0,0x84,0x13,0x55,0x56,0x56,0x56,0x59,0x35,0xfc,0x11,0xb5,0xdd,0x1e,0x35,0x9e,0x97,0xb5,0x2a, +0x39,0xf9,0x77,0xa1,0x79,0xc7,0x9a,0x6f,0x83,0xb2,0x0c,0xd9,0x51,0x55,0xc9,0x29,0xf7,0xc4,0xf3,0xf6, +0xd5,0xdd,0x0a,0xb9,0xd3,0x5a,0x87,0xb9,0xba,0xdf,0x45,0xcb,0x3b,0xd5,0xca,0x37,0x0b,0x9b,0xbf,0xb4, +0x2e,0x10,0x0e,0x6f,0x6b,0xf1,0xd6,0x76,0x90,0x87,0x25,0x5c,0x91,0x55,0x10,0x01,0x66,0x4a,0x45,0x68, +0x76,0x0c,0x1a,0x88,0xfb,0x05,0xea,0x2f,0x76,0x79,0xa3,0x89,0x83,0x44,0x78,0x6b,0x0e,0x63,0x15,0xf0, +0x0b,0x35,0x33,0x29,0xe0,0x4e,0xca,0x81,0x4a,0xb6,0xd1,0x8f,0xa2,0x88,0xec,0x47,0x21,0xfd,0x24,0x20, +0xba,0x04,0xcb,0x20,0x2d,0x93,0xc1,0x5c,0xc4,0x45,0xbe,0xf8,0x67,0x5e,0xb6,0xe8,0xd7,0x22,0xbb,0x6c, +0xc1,0xa5,0x04,0x3d,0xf4,0xaa,0xef,0x88,0xbe,0x39,0x38,0x7a,0x2b,0xdd,0x29,0xdb,0xdb,0xbe,0xd4,0xed, +0x6b,0x21,0x70,0x08,0xf7,0xd0,0xe8,0x69,0x3e,0xfa,0x6b,0x6f,0xb0,0xfd,0x63,0x6f,0xc0,0x36,0x07,0x65, +0x94,0xb6,0xe0,0x5e,0x1f,0xf9,0x5b,0x08,0xe2,0xfb,0x5b,0x94,0xfc,0xe1,0xcd,0x66,0xff,0x2f,0x3d,0xbf, +0xdd,0xca,0x00,0x1e,0x7e,0x0d,0xe0,0x37,0xca,0xfd,0xbe,0x47,0xbf,0xfa,0x93,0x30,0xdd,0x2a,0x83,0x59, +0xd8,0x52,0x56,0x0b,0x73,0xca,0x6c,0x0b,0x80,0xa7,0xfd,0xed,0xde,0xa8,0x3f,0x98,0xef,0x6c,0x3f,0xea, +0x8d,0x5a,0xf0,0xd1,0xa9,0x00,0x3b,0x24,0x3d,0xdc,0x7a,0xd2,0x1b,0xcc,0x09,0x8c,0xb2,0xe7,0x94,0xd0, +0x0b,0x96,0xa1,0x06,0x08,0x19,0xfe,0xd3,0x27,0x58,0x91,0x9d,0xa8,0xca,0x59,0x19,0xa2,0x96,0x53,0xbd, +0x16,0x40,0xa1,0x5e,0x0b,0x25,0xba,0x6a,0xc1,0x0c,0x51,0xcb,0xc2,0xd6,0x62,0x6a,0xcd,0x50,0x52,0x33, +0x23,0x49,0xcd,0xc4,0x87,0x9b,0xfc,0x5e,0x0d,0x62,0x89,0x10,0xcb,0x0a,0xe2,0xac,0x06,0x71,0x8a,0x10, +0xa7,0x0a,0x62,0x48,0x9a,0xe4,0x73,0xd6,0x7a,0x17,0xea,0x47,0x0b,0x52,0xfc,0xd8,0xa3,0xff,0x9f,0xa1, +0xf2,0x47,0xc0,0x40,0xfb,0xe8,0x6f,0x2f,0x0b,0xa2,0x00,0x5f,0xec,0xaf,0x95,0xb4,0xac,0x5b,0x66,0x34, +0x71,0xc9,0xa7,0x8f,0x35,0xb3,0x6d,0xfb,0xf7,0xc2,0x25,0x40,0xd0,0x2d,0xb3,0x50,0x18,0xb3,0x12,0xa4, +0x59,0x44,0xa1,0x79,0x3d,0x21,0x31,0xce,0x4a,0x10,0x14,0x35,0x12,0xb3,0xbc,0x1a,0xac,0x92,0xcf,0x68, +0xb2,0x23,0xf1,0x1c,0x69,0xc9,0x76,0x72,0x53,0xf4,0xd3,0xd5,0xf4,0x19,0xd5,0xaa,0x4a,0xd0,0xc9,0x8c, +0x26,0x04,0xd2,0xa4,0x47,0xb3,0xa8,0xd8,0x85,0x73,0x38,0x19,0x2f,0xcb,0x58,0xc4,0x69,0xb9,0x3c,0x5d, +0x74,0x50,0x9f,0x6e,0x63,0x43,0x69,0x06,0xe7,0x47,0xc9,0xf1,0xc6,0x46,0x0b,0xff,0x84,0x5a,0x61,0xa0, +0x48,0x53,0xe1,0x40,0xfa,0x48,0xc5,0x32,0x23,0x2a,0xb8,0xde,0xc3,0x28,0xf7,0xf3,0x42,0xa6,0xca,0x0a, +0xd7,0xfb,0x7e,0x15,0x1a,0x90,0x50,0x25,0xd1,0xad,0x52,0x92,0xd5,0xbb,0x07,0xf0,0xd2,0x9f,0x7b,0xd2, +0xa8,0xc3,0x9d,0x28,0x1d,0xee,0x61,0x83,0xd5,0xae,0x50,0x25,0x2e,0x8e,0x47,0xc6,0x17,0xe1,0x23,0x2c, +0x8a,0xab,0x06,0x09,0x59,0x39,0xed,0xd8,0xbc,0xa0,0x79,0x22,0xd5,0x64,0x52,0x75,0xa1,0x53,0xcb,0x0f, +0x50,0x50,0xc5,0xf6,0x67,0x52,0x34,0xa5,0x7d,0xe9,0xc2,0xa8,0x8a,0xd8,0xa4,0xe7,0x8d,0x81,0x78,0xbd, +0xf1,0x3c,0x3b,0xfd,0xec,0x59,0x02,0x3b,0x56,0x99,0x15,0x46,0x72,0x62,0xb2,0x36,0x4b,0x13,0xc8,0xd9, +0x54,0xac,0x03,0x63,0x80,0x71,0xb7,0x92,0x38,0x29,0x90,0x07,0x18,0xa2,0x1b,0xf8,0xa9,0x72,0xf7,0xac, +0x14,0xea,0xe5,0x12,0x2d,0x2f,0x49,0xe7,0x49,0x4a,0x83,0x6a,0x7a,0xce,0xf7,0x47,0x49,0xdd,0x95,0x3e, +0x82,0x76,0xb8,0x07,0xfe,0xc0,0xce,0xb7,0x2b,0xa8,0xa2,0x9e,0x1b,0x2d,0xe6,0x32,0x16,0x86,0x9c,0x22, +0xb9,0x1d,0xa7,0x17,0x9b,0xb6,0x43,0xf7,0xd6,0x81,0x10,0x01,0x1b,0x4a,0x9a,0x93,0x09,0xbb,0x53,0x45, +0x2e,0x91,0x38,0xc9,0xa3,0x4b,0xbe,0x0c,0x14,0x2d,0x65,0x7a,0xc6,0x0e,0x12,0x65,0x32,0x22,0x8d,0xa7, +0xf8,0x19,0x9c,0x98,0xc5,0x0d,0xe2,0x1f,0xac,0xfc,0x84,0x00,0x4f,0x88,0x26,0xb2,0xec,0x78,0xbe,0xcc, +0x6f,0x53,0x14,0xe1,0x44,0x49,0x7f,0x20,0xde,0x67,0x5d,0xa2,0x55,0x94,0xe3,0xba,0x24,0xae,0x37,0xcf, +0x10,0x47,0x29,0x44,0x52,0x0c,0x40,0x4d,0x54,0x99,0xc8,0x1e,0xac,0x62,0x8c,0x6a,0xdd,0x50,0xc0,0x27, +0xa4,0xf1,0x2d,0x85,0xc5,0x4e,0x24,0x39,0x51,0x70,0x4a,0x37,0xd3,0x98,0xa6,0x8c,0x20,0x31,0x57,0x2e, +0x8a,0xde,0x48,0x62,0x2e,0x49,0x14,0x96,0x58,0x71,0xc9,0xcf,0xf1,0xd7,0x1b,0xe4,0x9b,0x5c,0x94,0xe0, +0xd4,0x6d,0x82,0xac,0xc4,0x6e,0x51,0x8a,0x01,0x61,0x59,0xd9,0x96,0x18,0xc6,0x72,0xa7,0xa3,0x46,0xac, +0x76,0x19,0xa3,0xa7,0x55,0x87,0xb0,0xce,0x06,0x3e,0xa0,0x84,0x9d,0xd7,0xa0,0x66,0x17,0x53,0x87,0x95, +0xf2,0x7f,0xf3,0xdd,0xe1,0xd6,0x4d,0x98,0x59,0xca,0x52,0x60,0x24,0xbd,0x05,0xec,0xd2,0xe2,0x83,0x59, +0x37,0xc9,0xd2,0x39,0xcc,0xa2,0x81,0x5c,0xa3,0x2a,0x09,0xe3,0x22,0xd5,0xe4,0xa2,0x9a,0xa7,0x83,0x18, +0xfa,0x90,0x7d,0xb5,0x85,0xa3,0xa5,0xbd,0xb7,0x59,0x5b,0xe9,0xca,0x3d,0x94,0xd6,0xca,0x38,0x86,0x03, +0xc9,0xdc,0x7e,0x4b,0x15,0xdd,0x1d,0xe3,0x2b,0x89,0xa0,0x3b,0x39,0x9a,0x0b,0x37,0xce,0x43,0x95,0xef, +0x9e,0x6c,0x2a,0xbb,0x61,0x46,0xa9,0xfc,0xa6,0xc9,0x83,0x00,0xee,0x4d,0x1b,0xb7,0x02,0x1f,0xe3,0x8e, +0xc7,0x65,0x7c,0xc3,0x99,0x65,0xec,0x74,0xb7,0xa0,0xa4,0x4e,0x32,0xd8,0x23,0xd6,0xfb,0x43,0x19,0xda, +0x8e,0x64,0x10,0xb0,0xcb,0x1b,0xa2,0x68,0x8c,0x06,0x22,0xa9,0x9d,0x2b,0x12,0x97,0x95,0x19,0xb3,0x00, +0x17,0x67,0x42,0xa0,0xe5,0xd0,0x71,0x20,0xdc,0x47,0x08,0x27,0x8f,0x49,0x9a,0xc6,0x39,0x19,0x73,0x3c, +0x85,0xda,0x34,0xdb,0x8e,0x8d,0x0d,0xd1,0xca,0xba,0xd6,0x8a,0x84,0x20,0x23,0x01,0x60,0x97,0xea,0xad, +0x72,0x3e,0x3d,0x4f,0xdd,0x47,0xb6,0x21,0x05,0x2d,0x2a,0x3c,0x93,0xd6,0x00,0x24,0x4c,0x62,0x74,0xd0, +0xae,0x2e,0x41,0xc4,0xda,0xc8,0x37,0x34,0xa6,0x6f,0xc4,0x67,0xba,0x34,0x00,0x71,0xbc,0xb5,0x91,0x85, +0x15,0xe9,0x3f,0x5f,0x7a,0x83,0x28,0x74,0xa2,0x09,0x8d,0xe8,0x7a,0xd2,0x2e,0xb8,0xd7,0xcb,0xd8,0x84, +0x2a,0x5c,0x50,0x07,0x51,0x69,0x42,0x5d,0xb8,0xa0,0xfe,0x1e,0x59,0x2d,0xe6,0x2e,0xa8,0x7d,0xb4,0xda, +0xd7,0xa1,0xa6,0x2e,0x28,0x92,0x47,0x9a,0x70,0x63,0x17,0x1c,0x8a,0xfc,0x4c,0xb0,0xc8,0x05,0x46,0x22, +0x35,0x13,0x6e,0xe1,0x82,0x53,0xe3,0x76,0x2d,0xec,0x51,0xd1,0x96,0xc3,0x72,0x21,0x26,0xa7,0x7c,0x24, +0x56,0xbb,0xe1,0xe2,0x44,0x0d,0x2f,0x7b,0xda,0xce,0xc2,0xc7,0xbd,0xcd,0xbc,0x2b,0x0c,0x93,0x86,0x56, +0x73,0x96,0xc8,0x8b,0xaf,0xc7,0x18,0x53,0x5e,0x78,0xfe,0xff,0xbd,0x73,0x2f,0xcd,0xe0,0x4e,0xdd,0x55, +0x13,0x0e,0xaf,0x09,0xdd,0xca,0xfc,0x6a,0x63,0x63,0x3d,0x91,0xd7,0xe1,0xde,0x30,0xd5,0xdd,0x14,0x78, +0x5e,0xc0,0xc8,0xc0,0xaf,0x6b,0x8c,0x77,0x68,0x9a,0x2e,0xea,0x8a,0x07,0xf8,0x0a,0x39,0x6f,0xeb,0x3a, +0x0c,0x82,0x7b,0x63,0xaf,0x06,0xc2,0xbf,0x97,0x72,0xb3,0xee,0x2d,0x80,0x99,0xc2,0x77,0xdf,0x76,0x63, +0x09,0xe1,0xae,0xcb,0x51,0x04,0x58,0x08,0xb8,0x51,0xf0,0x3a,0x67,0xcf,0x1f,0x3a,0xd2,0xf3,0x36,0x42, +0x5e,0x8b,0x88,0x31,0xa5,0xd9,0x9f,0x6b,0x5f,0x04,0x1a,0x6a,0x58,0x28,0x16,0xad,0xe0,0x32,0xef,0x1c, +0xab,0xbb,0x51,0x7b,0xc2,0x38,0x08,0x52,0x96,0x2a,0x5a,0x15,0x21,0x1a,0x08,0xf7,0x13,0x2a,0xf5,0x1a, +0x03,0xc3,0x1a,0x36,0xac,0x4b,0x40,0xe2,0x92,0x3b,0xdb,0x99,0x18,0x7d,0xef,0x68,0xd4,0x9b,0xdc,0x8a, +0xde,0xcd,0x25,0x1a,0xe9,0x5d,0xd9,0xb9,0x6a,0x88,0x60,0xbf,0x66,0x96,0x11,0xe6,0xa9,0x3e,0xfc,0xb3, +0x3b,0x0f,0xff,0xec,0x96,0xe8,0xcc,0x6e,0x41,0xce,0xd6,0xb2,0xa3,0xd0,0xeb,0xf4,0xfd,0xcd,0x53,0x7f, +0x4b,0x7e,0xca,0xe9,0x71,0xbb,0x2b,0x9b,0xc1,0xd3,0x57,0xc7,0x1f,0x87,0xb1,0xd3,0x34,0x23,0xc4,0x6e, +0xa0,0xd5,0x69,0x5e,0xd2,0x44,0x3e,0x07,0xc9,0xb3,0x18,0x2b,0x65,0x26,0x7c,0xd4,0x3b,0x26,0xdf,0xc1, +0x55,0x42,0xff,0x98,0xb9,0x24,0x3c,0xb6,0xdc,0x96,0xc1,0xb5,0x26,0x13,0xf3,0x08,0x2e,0xa4,0xc3,0x16, +0xe8,0x5d,0x10,0x85,0xfd,0x80,0xf6,0xa2,0x44,0xee,0x45,0x41,0x0a,0x49,0xb0,0xf0,0x03,0xf4,0xc7,0x3f, +0x43,0x9f,0xfc,0x21,0x4a,0x8a,0x50,0xce,0xd3,0x1f,0x26,0x5d,0x34,0xe3,0x64,0x43,0xe2,0x6e,0x04,0x60, +0x96,0xd8,0x06,0xae,0x3c,0x30,0x59,0xeb,0xa9,0x53,0x5c,0x38,0xb5,0xd4,0xb1,0x0f,0x95,0xc3,0x35,0x16, +0xaa,0x87,0xe3,0x0b,0x1a,0x28,0xba,0x17,0xbc,0x1c,0xf7,0x42,0xfb,0xe9,0xa0,0x7a,0xa1,0xe0,0x25,0xb4, +0xbe,0x87,0xd7,0x5f,0x7b,0x6f,0xa5,0x59,0x77,0x16,0xee,0x09,0x01,0x66,0x4d,0x86,0x38,0x3c,0xb3,0xc4, +0x48,0x68,0x16,0x34,0x27,0x09,0xd2,0x84,0xfe,0xcf,0xc6,0x45,0x29,0x49,0x93,0xce,0xba,0xe4,0x79,0x9d, +0xc4,0x49,0xbd,0xa0,0x47,0xe2,0xa4,0xe0,0xac,0x12,0x31,0xc9,0xb4,0x6b,0xe5,0x18,0x45,0x31,0x86,0x44, +0xa4,0xf5,0xfa,0xe8,0x4f,0x6b,0xfd,0xd2,0x9e,0x8b,0x44,0xc7,0xa6,0x8e,0x8e,0x7d,0xfb,0x26,0xcc,0x3f, +0x2f,0xc2,0x69,0x53,0xdf,0x82,0xcb,0xf0,0x42,0x5c,0xc9,0x7e,0x82,0x4b,0x73,0x94,0xbf,0xc2,0xa8,0x60, +0x28,0x74,0x45,0x44,0x7b,0x78,0x7a,0x5c,0x12,0xbb,0x81,0x03,0x7f,0x50,0x66,0x0b,0x48,0x6f,0x22,0x41, +0xdf,0xc7,0xfa,0x4c,0xe8,0x7e,0x23,0x74,0x0f,0xa1,0x2f,0x34,0xca,0x5e,0xc2,0x97,0x49,0x3b,0x74,0xc0, +0x20,0x40,0x8c,0xb4,0x6b,0x8e,0x61,0x64,0x53,0x45,0x3d,0xc9,0x0a,0x9a,0x7c,0x58,0x45,0x93,0x8f,0xe1, +0x87,0x46,0x9a,0x8c,0xc3,0x8f,0x37,0xd0,0x64,0xec,0xa2,0x09,0x4e,0x50,0xbd,0x8b,0xd8,0xc1,0xb1,0x8b, +0x1c,0x08,0x6f,0x82,0x7d,0xd4,0xe8,0x30,0x16,0x5f,0xf5,0x2e,0xff,0x5a,0xeb,0xb2,0xf6,0x86,0x2b,0x3a, +0xfd,0xeb,0xaa,0x4e,0xff,0x1c,0xfe,0xda,0xd8,0xe9,0xcf,0xe1,0xcf,0x37,0x74,0xfa,0xb3,0xb3,0xd3,0x3c, +0xb2,0xdc,0x75,0xd1,0x9b,0xcf,0xce,0x4e,0x33,0x60,0xaf,0x02,0xfb,0x59,0xeb,0xf4,0x67,0xf1,0x55,0xef, +0xf4,0xd7,0x5a,0xa7,0xab,0x17,0x5f,0xd1,0xe7,0xaf,0xab,0xfa,0x7c,0x1e,0x7e,0x6d,0xec,0xf3,0x41,0x78, +0x7e,0x43,0x9f,0x0f,0x56,0xf4,0x99,0xc7,0x10,0x55,0xee,0xb1,0xaa,0x15,0x7d,0x66,0x40,0x9a,0xf0,0xe7, +0x5a,0x9f,0x0f,0xc4,0x57,0xbd,0xcf,0xef,0x6a,0x7d,0x7e,0x6d,0x75,0xf9,0xdd,0xaa,0x2e,0xbf,0x09,0xdf, +0x35,0x76,0xf9,0x4b,0xf8,0xe6,0x86,0x2e,0x7f,0xa9,0x75,0xf9,0xbb,0xb3,0x5e,0x0f,0x8b,0x9a,0x19,0xdd, +0xfe,0x13,0xfe,0xef,0x47,0x84,0x38,0x73,0x41,0xfc,0x20,0xff,0x03,0x88,0x9e,0x13,0xe2,0x31,0xe5,0x9c, +0x39,0x72,0x9e,0x68,0xb5,0xf7,0x7a,0x2e,0x88,0xbf,0x68,0xb5,0x9f,0xb9,0x20,0xfa,0x0a,0xf5,0x37,0x1a, +0xd9,0xbf,0x88,0xaf,0x3a,0xd9,0x5f,0xd7,0xc8,0xae,0xd4,0x6d,0x04,0xd9,0x5f,0xaf,0x22,0xfb,0x89,0xdb, +0xd1,0x81,0xd2,0xb6,0x6d,0x2d,0x61,0xe7,0x5f,0xf8,0xc3,0x93,0x6e,0x6e,0x1f,0x6b,0x27,0x78,0x04,0x9e, +0x74,0xa7,0xf5,0xf4,0x29,0xa6,0x8f,0xeb,0xe9,0x63,0x3e,0xf3,0xf6,0xc3,0xd7,0x8d,0x43,0xfd,0x36,0xdc, +0xbf,0x61,0xa8,0xdf,0x36,0xcc,0xee,0x13,0xb4,0x78,0x0e,0xf0,0xef,0x54,0xfc,0x1d,0xf3,0x92,0x7d,0xdb, +0x30,0xcb,0x2d,0xf4,0x16,0x4e,0xc3,0xeb,0xe6,0x54,0xac,0x7a,0x5f,0x1b,0xa2,0xb7,0xe2,0xab,0x3e,0x44, +0xef,0x6b,0x43,0xa4,0x54,0x89,0xc4,0x10,0xbd,0x5f,0x35,0x44,0xbb,0x37,0x0f,0xd1,0x29,0x9c,0x63,0xc3, +0xdd,0xfa,0x10,0xed,0xe2,0x10,0xed,0xd6,0x87,0x68,0x17,0x87,0x68,0xb7,0x3e,0x44,0xbb,0x72,0x88,0x5e, +0x85,0xef,0x1b,0x87,0xe8,0x30,0x7c,0x75,0xc3,0x10,0x1d,0x36,0x0c,0xd1,0xae,0x18,0xa2,0x5d,0x31,0x44, +0xbb,0x72,0x88,0x0e,0xeb,0x6b,0xa0,0x47,0x6b,0xe0,0x95,0x46,0xe0,0x43,0xf1,0x65,0x12,0xf8,0x56,0xac, +0xac,0x21,0x87,0xb6,0x9e,0x21,0x6e,0xe6,0x64,0x9b,0x44,0x3d,0xc4,0x58,0x92,0xf1,0x00,0xb1,0xa9,0xe5, +0x1d,0xd8,0xd4,0x06,0x59,0x05,0xce,0x85,0xa4,0x91,0xdd,0x2b,0xdc,0xe5,0x84,0xd6,0x00,0x3e,0x1b,0x3b, +0xf3,0x85,0xfa,0x22,0x00,0x08,0x6d,0xf0,0xd3,0xac,0x68,0x6d,0x6f,0xca,0x47,0x5d,0x98,0x48,0x3e,0xfc, +0xaf,0x90,0x9a,0xe1,0x45,0x92,0xba,0x72,0xe7,0x61,0x22,0x2f,0x40,0x5b,0xdb,0xc0,0xf9,0x26,0xea,0xf2, +0xb1,0xb5,0x3d,0x2c,0x34,0x37,0xc5,0xc1,0xbc,0x9d,0x6d,0x6a,0xb0,0x74,0xe9,0xf0,0x03,0x01,0x02,0xc3, +0xeb,0x05,0x93,0x4e,0xba,0xa9,0x97,0x17,0x20,0x7d,0x4b,0xea,0x68,0xf8,0x42,0x91,0x9e,0x7f,0x9a,0x21, +0x36,0x36,0x7a,0xb6,0xd8,0x12,0xb8,0xd3,0x91,0xf0,0xb6,0x9d,0x2d,0xa2,0x53,0x60,0xfa,0xf1,0x48,0x1b, +0xd8,0x49,0xfd,0x4e,0x2b,0xef,0x5e,0x3c,0xed,0x6e,0x8f,0xba,0xdb,0x03,0xf8,0x25,0x44,0x17,0xb5,0x1b, +0x70,0xed,0x44,0x9b,0x35,0x8e,0xd5,0xd2,0x55,0x56,0x8e,0xd4,0x70,0xa9,0x11,0x03,0x28,0xbc,0x39,0x33, +0x6f,0x72,0xdc,0xfc,0xa9,0x4b,0x08,0x65,0x34,0x7f,0xda,0xd8,0xfc,0xc2,0x55,0x56,0x35,0xbf,0xd0,0x9a, +0x6f,0xf5,0x3b,0x30,0xbc,0x70,0x4d,0x74,0xa1,0xb0,0xe7,0x92,0x70,0x19,0x28,0xac,0xba,0x9c,0x38,0xca, +0x2a,0x14,0xce,0x6c,0x14,0x2e,0xfc,0xcd,0x3d,0x17,0x0a,0x53,0x97,0xf8,0xec,0xc6,0x6b,0x84,0xbc,0x43, +0x38,0xca,0x2a,0x14,0x2e,0x6c,0x14,0x72,0x7f,0x73,0xea,0x42,0xe1,0xd2,0x2d,0x9b,0x33,0x90,0xb8,0x6c, +0x44,0xe2,0x83,0xbb,0xb4,0x42,0xe3,0x83,0x8d,0xc6,0xd4,0xdf,0xbc,0x74,0xa1,0xf1,0xd1,0x29,0xfa,0x33, +0xb0,0xf8,0xd8,0x88,0xc5,0xd8,0x59,0x58,0x21,0x31,0xb6,0x91,0x18,0xfb,0x9b,0x1f,0x5d,0x48,0xfc,0xea, +0x16,0x2c,0xde,0xc8,0xce,0x4b,0x5e,0xde,0x59,0x5a,0xa1,0xf1,0xb3,0x8d,0x46,0xe4,0x6f,0xfe,0x6a,0xa3, +0x71,0x97,0x1d,0xdf,0x15,0xc8,0xc0,0x8c,0xb1,0xa2,0xbf,0x5b,0x36,0xbc,0x5a,0xde,0xa6,0xa5,0x37,0xa4, +0x28,0x71,0xd7,0x93,0xc5,0x7e,0x7d,0xb1,0x8d,0x57,0xc4,0x63,0xf8,0x54,0x3e,0x32,0xf9,0xf2,0xd9,0x49, +0x83,0xb1,0x41,0xac,0xb7,0x25,0xe1,0x98,0x0a,0x55,0x0a,0x98,0xb8,0x95,0x3d,0x83,0x67,0xb8,0x60,0x6a, +0x69,0xc2,0x12,0x76,0x5f,0x23,0xab,0xa2,0xb4,0xee,0xc5,0x4e,0xf7,0xf1,0x48,0xd4,0x41,0x29,0x1e,0x3e, +0x5f,0x44,0xf4,0x5c,0x6d,0x25,0x5f,0x62,0x64,0x43,0x14,0x00,0xdf,0x40,0xb4,0x5d,0x20,0xd6,0x05,0xf9, +0xe4,0xcc,0xb3,0xb9,0xa1,0xcf,0x21,0x45,0xab,0xd5,0x33,0xaa,0x7e,0xb6,0x46,0x7a,0x39,0x8f,0xd5,0x9b, +0x7a,0xeb,0xca,0xf3,0x91,0x3c,0x2d,0x5b,0xd6,0x33,0x95,0x46,0x16,0x3a,0x2c,0x8d,0x33,0x5c,0x6a,0x74, +0xe4,0xec,0x97,0x14,0x9f,0x48,0x4c,0x07,0xa6,0x6c,0x7e,0x51,0xf9,0xd8,0x23,0x8a,0x12,0x6c,0xd8,0x00, +0x5a,0x39,0x39,0x65,0xc0,0x7f,0xdc,0x04,0xf8,0x0f,0x7a,0x40,0x56,0x6b,0xc7,0x64,0x0e,0xb8,0x57,0x19, +0xf4,0x72,0x15,0x0f,0x90,0x86,0x2d,0x27,0x40,0xc5,0x04,0x48,0xac,0x3b,0x09,0x3e,0xa1,0x15,0xf8,0xa0, +0xdd,0xc5,0x83,0xbb,0xa3,0x9d,0xd9,0xfe,0x56,0x4b,0xff,0x42,0x1b,0xb1,0x8e,0x28,0xf7,0x0f,0xbd,0x1c, +0x2c,0xd4,0x8e,0x7e,0x90,0x53,0x39,0xed,0x93,0x98,0xa3,0x46,0xe7,0x60,0x3e,0xcb,0xf8,0x15,0x42,0xad, +0x44,0xe3,0x39,0x9f,0x09,0x97,0x65,0x7b,0x73,0xe4,0x2d,0x89,0xe7,0x13,0x78,0x4a,0x7f,0x62,0xf4,0xe5, +0xaf,0x40,0xdb,0xc0,0xfa,0xe6,0xca,0xb1,0x33,0xaa,0x6e,0xf8,0xf0,0x57,0x77,0x8d,0x85,0xe9,0x0e,0x1d, +0xbc,0xd4,0xd0,0xc0,0x9b,0x93,0xfe,0xdd,0x84,0x22,0x22,0x4c,0x30,0x22,0x42,0xd1,0x45,0x0f,0x6a,0x1b, +0x1b,0x93,0xa7,0xfc,0x4b,0xf9,0x52,0x23,0x80,0x1e,0x57,0x3c,0x43,0xcb,0xbb,0x94,0x38,0x1a,0xb4,0xbf, +0xab,0xf4,0xf2,0xe6,0x5b,0x29,0x60,0xa2,0xf8,0x33,0x7f,0x38,0xa3,0xb0,0x0b,0xb3,0x36,0xfa,0xfe,0x0f, +0xe6,0xfa,0x87,0x7c,0x9f,0x7e,0x5d,0x5c,0xb4,0x66,0xc1,0x24,0x88,0xe0,0x8c,0xad,0x6c,0x2f,0x6b,0xf3, +0xcc,0x14,0xef,0x37,0xce,0x37,0xa9,0x5d,0x89,0xd4,0x6d,0x98,0x12,0xfe,0x56,0x45,0xa9,0x5b,0xcc,0x00, +0xad,0x9e,0x7b,0x0c,0x92,0xd1,0x18,0x73,0x5e,0x40,0x05,0xa0,0xd9,0x7c,0xa7,0x8f,0x1a,0x87,0x43,0x49, +0xef,0xa5,0x4d,0xef,0xd1,0x32,0xec,0x0d,0x54,0xee,0x4e,0xbf,0x53,0x1f,0x8f,0xa5,0x3e,0x60,0x4b,0xd8, +0x00,0xeb,0x30,0xcb,0xa7,0xdd,0xc7,0x6d,0x57,0x49,0x1c,0x82,0x4c,0x3b,0xcf,0x96,0x1a,0xcb,0x2b,0x18, +0x5e,0xc7,0x62,0xa7,0xb7,0x41,0x11,0x31,0x01,0x08,0x8a,0xd7,0xbb,0x7e,0x67,0x09,0x63,0x37,0x85,0x7f, +0x63,0x67,0x11,0xf1,0x50,0x68,0x16,0x8a,0xba,0x79,0xc0,0x05,0xdd,0x85,0xf8,0xd5,0xb0,0x5e,0x06,0x1b, +0x42,0x85,0x45,0x57,0x99,0xd7,0x66,0x11,0x9c,0x57,0xd8,0x40,0x41,0x33,0xcb,0x55,0x80,0x1e,0x4d,0xcd, +0x02,0x51,0x77,0x26,0xf0,0x72,0x17,0xa1,0x17,0xd4,0x7a,0x11,0x6c,0xa5,0x09,0x2d,0xf1,0xb2,0x59,0x15, +0xa2,0x04,0x52,0xbb,0xbc,0x5e,0xa1,0x21,0x31,0x15,0xca,0x21,0x4d,0xac,0x01,0x9d,0x0c,0x2b,0x8b,0xb3, +0xba,0xa2,0xad,0x1b,0x6c,0xea,0x01,0xb8,0x9c,0xe9,0xe6,0xc2,0x22,0x14,0x95,0x14,0xa4,0x67,0xc6,0x9d, +0xb0,0x27,0xcf,0x76,0x3e,0x6e,0x0d,0x87,0x7b,0x7a,0xfa,0xa6,0xda,0x5a,0xfa,0x3d,0xad,0x02,0xa9,0xa6, +0xeb,0xc8,0x68,0x3c,0xe6,0xe3,0x15,0x27,0x74,0x51,0xef,0x5f,0xf5,0xe6,0xa9,0x7b,0x08,0x83,0x7e,0xcb, +0x4e,0x26,0x23,0x53,0xed,0x26,0x81,0x12,0x83,0xd5,0xdc,0x53,0x51,0x1b,0x05,0x72,0x00,0xc9,0x15,0xd6, +0x9e,0x8b,0x62,0xd5,0x00,0x33,0x3b,0x08,0x3b,0x90,0x3e,0x12,0xf2,0x91,0x36,0x99,0xa3,0x16,0x24,0x04, +0x30,0x4c,0xf0,0x6f,0x0c,0xff,0x22,0x1d,0x72,0x36,0xd2,0xe6,0x17,0x42,0xce,0x00,0xa2,0x80,0x7f,0x17, +0x36,0x64,0x34,0x32,0x27,0x95,0xc8,0xbe,0xb1,0x4f,0x88,0x81,0x41,0xb9,0x80,0xec,0xb1,0x81,0x7e,0x52, +0x71,0x94,0xde,0xd5,0xd1,0x49,0xbb,0x70,0x90,0xa8,0x71,0x23,0x59,0x17,0xf8,0x42,0xd8,0x3b,0xa6,0x61, +0x0e,0xff,0x1f,0x87,0x89,0xf0,0xf6,0x8c,0x46,0xc7,0x19,0x4c,0x8c,0xa2,0x7a,0x1d,0x97,0x26,0xe0,0xdc, +0x84,0x1a,0x88,0xac,0x3b,0x0b,0x53,0xe8,0x55,0xd6,0x2d,0xe0,0x6f,0x01,0x7f,0x2f,0xe0,0xef,0x45,0x33, +0x7b,0x5b,0x63,0x84,0x23,0xb1,0x9c,0x34,0xee,0xf6,0x46,0x4e,0x98,0xfb,0x6d,0x59,0xa3,0x6b,0x31,0xba, +0xcc,0xe1,0xa1,0x4c,0xd2,0xf5,0x4d,0x56,0x4f,0x43,0x1c,0xa3,0xdf,0x41,0xcb,0x19,0xd1,0xb2,0x20,0x5a, +0x5e,0xac,0xa2,0xa5,0x92,0xa7,0xd9,0xb4,0xcc,0x81,0x76,0x39,0x8d,0x47,0x0a,0xf3,0x09,0x47,0x24,0x85, +0x39,0xf5,0x2f,0xa7,0x65,0xdd,0xb2,0xdf,0x41,0x4b,0x9e,0xc0,0xb7,0xa6,0x25,0xcd,0x62,0xe7,0x5a,0x5b, +0x53,0xd4,0x24,0x3d,0xaf,0x2a,0x7c,0x80,0xdc,0x8e,0xe2,0x3b,0xf4,0xb8,0xbc,0x4f,0x8f,0x67,0xd9,0xa5, +0xdb,0xc7,0x35,0x33,0xf0,0x01,0xab,0x5a,0xa0,0xcf,0x06,0x4b,0x0b,0xc5,0xdc,0x70,0xf1,0x99,0x99,0xdd, +0xe3,0x92,0x3f,0x52,0xa9,0xb9,0x56,0xac,0x54,0xe2,0x05,0x5a,0xa2,0xe0,0x71,0xbd,0x87,0x6a,0x75,0x42, +0x56,0x75,0x85,0x7e,0x6a,0xf3,0x5b,0x73,0x22,0x52,0x37,0xe3,0xb5,0xf1,0x26,0x4f,0x2e,0x6f,0x9b,0x2b, +0xa9,0x33,0xb4,0xe2,0x8d,0xfe,0xd6,0xba,0xb6,0x2b,0xee,0xac,0x9a,0x4e,0x7d,0xce,0x77,0x45,0xb4,0x1b, +0x88,0x26,0x30,0x20,0xa8,0xd2,0xa3,0xf9,0x0e,0x46,0x55,0x1e,0xdd,0xfd,0x2f,0xaa,0x85,0x75,0x51,0x35, +0x8f,0x34,0x59,0x9d,0x56,0xf9,0xbe,0xd2,0xf4,0x2b,0x6a,0x47,0xb2,0xd2,0x1d,0x93,0x3c,0x64,0x65,0x43, +0x5e,0x9c,0xc2,0x95,0x6d,0x7e,0x08,0xb4,0xc6,0xbb,0xca,0xed,0xa9,0x3b,0x4c,0x9f,0x66,0xa3,0xaa,0x1a, +0x15,0x57,0x48,0xd5,0x87,0x01,0xc4,0x06,0xa9,0x3d,0x08,0x3b,0x59,0x5b,0xd7,0x8f,0xe3,0x64,0x60,0xe2, +0x0c,0xa0,0x8d,0x8d,0xd5,0x15,0xdb,0x95,0x76,0xea,0x55,0xb6,0xad,0x2a,0xaf,0x57,0xe9,0x66,0x22,0xa5, +0x5d,0x56,0xeb,0x86,0xb6,0x04,0x7e,0x84,0x8d,0xaa,0x0f,0x74,0xf9,0xc4,0xa1,0x7c,0xbf,0x2c,0x4d,0xe5, +0x38,0x73,0x58,0x1b,0x07,0x8f,0x95,0xf2,0x68,0xb3,0x10,0x5a,0xb6,0xe1,0xd5,0xf5,0x2a,0xed,0x60,0x43, +0x01,0x44,0xc7,0xb8,0xd1,0x6f,0xbb,0xd4,0x05,0x15,0x5e,0x34,0x24,0xb4,0xa5,0xc7,0x8a,0x5d,0x69,0xc8, +0xe2,0xb5,0x18,0x97,0x87,0xc9,0x79,0x0c,0xd4,0xd5,0x1d,0xc7,0xc3,0x4e,0x20,0xae,0xf5,0x0d,0x0a,0xb3, +0xd7,0x32,0x9e,0x82,0x23,0x18,0xb5,0xf4,0xa6,0xb4,0x9b,0x4e,0x72,0xdc,0xf4,0xba,0x9b,0x6b,0x2f,0x13, +0x58,0x6a,0xd9,0x97,0x2d,0xc0,0xe6,0xc6,0x06,0x5d,0x58,0x6a,0xd9,0x59,0x1a,0xb3,0x5a,0xab,0x61,0x0a, +0x79,0x0b,0x84,0xaf,0x8d,0xe1,0xa8,0x69,0x59,0xdf,0x67,0x00,0x94,0xe9,0x8b,0xb6,0xb6,0xbf,0x7d,0x6b, +0x29,0x33,0x81,0xbc,0xda,0x22,0x84,0xa8,0x89,0xb6,0x09,0x5c,0x10,0x5c,0x33,0xf0,0x5f,0xd3,0x29,0x46, +0xb5,0x10,0x11,0xc7,0x5d,0x28,0x92,0x8e,0xae,0x53,0x7a,0xb3,0x0a,0x3b,0xd4,0xce,0xd1,0xb9,0xc8,0xaa, +0x75,0x7f,0x08,0x87,0x73,0x52,0x71,0x91,0x05,0x46,0x55,0xab,0x37,0x7b,0x6a,0x05,0x72,0xfb,0x03,0xda, +0x4d,0xaa,0x55,0xa4,0x9c,0xb2,0xc3,0x84,0x18,0x99,0xc8,0xf4,0xd0,0x3a,0x42,0x02,0x4a,0xbf,0xee,0x1b, +0x1b,0xeb,0x80,0xb5,0xe7,0x99,0x64,0xd4,0x6a,0x67,0x3b,0x3f,0x29,0xa3,0xd3,0xbb,0x53,0x37,0x76,0xb8, +0xf3,0x50,0xf3,0xd9,0x28,0xa5,0x88,0xb9,0xb1,0xf1,0x6b,0xa2,0x42,0xb8,0x3d,0x89,0x01,0x15,0x6d,0x0b, +0xfd,0x6c,0xcf,0x85,0x8f,0x65,0x7a,0xf0,0x3b,0x71,0x22,0x91,0xc3,0x6a,0x8d,0xf0,0x64,0xb5,0x46,0xb8, +0x34,0x69,0x91,0xd6,0x38,0x14,0x7a,0x08,0x50,0xf7,0xa5,0xd1,0x93,0x99,0x4c,0xc7,0x57,0x3d,0x4e,0x85, +0x70,0x66,0x7e,0x85,0xb9,0x83,0xa3,0xe3,0xeb,0x4a,0xf4,0x07,0x3c,0xa1,0x65,0x6c,0x29,0x65,0x7d,0x64, +0x73,0x19,0x51,0x85,0xdd,0xc5,0xb2,0x98,0xb5,0x8a,0xa3,0xec,0x18,0x67,0x8b,0xde,0xf1,0x62,0x59,0xa0, +0x8a,0x6c,0x3c,0xe1,0x48,0x75,0x1e,0x30,0xa8,0x0e,0xa2,0x56,0x66,0x29,0x7f,0xdc,0x18,0xaf,0x9b,0x83, +0x8c,0x6b,0xa7,0xb6,0x6c,0x1d,0x23,0x4f,0x5b,0x94,0x89,0xa3,0xcb,0xd8,0xb8,0x19,0x4f,0x40,0x28,0xef, +0x9e,0xce,0xb3,0x22,0x2e,0x4a,0x4d,0xda,0x28,0x75,0xdb,0xab,0x21,0xa9,0xf5,0x04,0x98,0xc9,0x96,0x92, +0x79,0xdf,0x46,0xc4,0x4b,0x02,0x54,0x0e,0xe2,0x2d,0x04,0x44,0xc8,0xb1,0xa8,0x5e,0xb2,0xe8,0x0a,0xb1, +0x75,0x74,0xe8,0xdf,0xaf,0x2b,0x77,0xe8,0x81,0x6d,0x5d,0xfd,0xef,0xd2,0x85,0xfb,0x8c,0x86,0xdb,0x08, +0xfb,0x3f,0xb9,0x47,0xba,0xb3,0xa5,0x3f,0xfe,0xf9,0x22,0x59,0xd1,0x79,0xb8,0xb8,0x36,0x75,0x1e,0xb9, +0xed,0x48,0xdb,0x76,0xb5,0xcb,0x90,0x69,0xce,0xe3,0x5f,0x45,0x0d,0x0c,0x42,0x56,0x75,0x9d,0x77,0x6b, +0x6a,0xe4,0xe4,0xf9,0xfb,0x77,0x87,0x27,0x87,0xc0,0x92,0xbf,0x7a,0xb1,0x7f,0xf2,0xe2,0xef,0x2f,0xde, +0x1d,0x1e,0x60,0x7b,0xf7,0xb7,0x37,0xcb,0xee,0x69,0x6f,0x26,0xae,0xec,0xd9,0xca,0x0d,0xd8,0xd7,0xb7, +0xf6,0x54,0x6d,0xed,0x73,0xbc,0xbc,0x43,0x55,0xa8,0xf5,0x3b,0x9c,0x3c,0x9d,0xcb,0x3d,0x7e,0x02,0x7b, +0x7c,0x85,0x8f,0xd7,0x6e,0x79,0x40,0xb2,0xf9,0xd1,0xe4,0xb8,0x8b,0xd1,0x64,0x8a,0x45,0x74,0x1a,0x8f, +0x3c,0x6f,0xe0,0x75,0xbd,0xb6,0x99,0xea,0x07,0xf4,0xcd,0x21,0xa3,0x72,0xff,0x5a,0x1b,0x49,0x60,0x00, +0x2a,0x43,0x4c,0xf1,0xac,0x14,0xb9,0xde,0xbe,0xf0,0x5e,0x7b,0xab,0x79,0xca,0xd6,0x4b,0x99,0x3d,0x35, +0x61,0x7c,0x7d,0xbe,0x71,0xb8,0x3d,0x70,0x39,0x17,0xd9,0x9d,0x26,0x67,0xae,0x26,0x67,0x59,0x0b,0xfb, +0x27,0x94,0x5a,0xfe,0x88,0xc5,0x2a,0xbd,0x10,0x3a,0x89,0x54,0x3a,0x16,0x25,0x45,0x1e,0xa5,0x88,0x81, +0xe6,0x69,0xab,0xb9,0x0f,0x73,0x76,0x9e,0xba,0xbe,0x66,0xe2,0xd9,0x35,0xec,0xad,0xe0,0x88,0x75,0x85, +0xab,0x2a,0x6f,0xe2,0xba,0xcb,0xfa,0xad,0xdd,0xbe,0xb2,0x5f,0x1b,0xbb,0x88,0xe1,0x03,0xcf,0xb6,0x6a, +0xe7,0x4b,0x8c,0xd3,0xd8,0xb4,0x62,0x77,0x9d,0xa6,0xa8,0xcd,0x24,0xaf,0xe2,0x36,0x28,0x5b,0x2b,0x6d, +0x08,0x0a,0x9d,0xb3,0x28,0x4c,0xce,0x22,0x72,0x70,0x16,0x85,0xb8,0x4c,0xa0,0xac,0x3d,0xd6,0xc2,0xbf, +0xe2,0xd5,0xe6,0xab,0x79,0x85,0xf2,0x8e,0xd8,0x12,0x1e,0xd7,0x3a,0x89,0x95,0x16,0x84,0xf2,0x31,0x4c, +0x41,0x7b,0xfd,0xb7,0xae,0xcc,0xf0,0x43,0x78,0x3d,0xd2,0xef,0x53,0x72,0x5d,0xc5,0x32,0xd6,0x2a,0x86, +0xe7,0x54,0x61,0x58,0xb3,0xdf,0x92,0xf9,0x3c,0xa2,0x78,0x98,0x2e,0xcd,0x39,0x15,0xc3,0x4f,0x58,0x02, +0x84,0xdd,0x6d,0xff,0x46,0xdc,0x4d,0x73,0x5e,0xf6,0x85,0x98,0x4c,0xa4,0x23,0xc4,0x0f,0xb0,0xba,0xdf, +0xd3,0xdb,0xae,0xf2,0x85,0xb8,0x10,0xc1,0x3a,0x07,0x6b,0xd1,0xb8,0xc8,0xe6,0xcb,0x32,0x1e,0xae,0xa1, +0x48,0x09,0x98,0xd0,0x35,0x12,0x0b,0xe1,0x0f,0x61,0xca,0x81,0x3f,0xd9,0x7c,0x03,0x7e,0x69,0x6e,0x13, +0x79,0xba,0x2a,0x17,0x23,0x30,0xb0,0xc2,0xbf,0xc8,0xb3,0xaf,0x6f,0x26,0xad,0x7a,0xdb,0x8d,0x0f,0x67, +0x43,0x15,0x85,0x29,0xb7,0xbc,0xf1,0xb1,0xa0,0x43,0x6c,0xf1,0xfb,0xf1,0x3c,0xc2,0x25,0x57,0x55,0xf9, +0x6c,0x39,0x7d,0x99,0x7c,0x31,0xee,0xb2,0x88,0x54,0xfc,0xc7,0x22,0x15,0x07,0x3d,0x76,0xdf,0x7f,0x56, +0xd2,0xa3,0x67,0x8c,0x32,0x1f,0xb8,0xa9,0xae,0x8a,0x2c,0xd5,0xa3,0x3b,0xf3,0x35,0xcc,0xbc,0x16,0x87, +0xf4,0xd2,0xa2,0xea,0x6d,0xe1,0xec,0xd9,0xf9,0x7f,0x12,0x82,0xdd,0xc0,0xf4,0x70,0x03,0x00 }; \ No newline at end of file diff --git a/code/espurna/system.ino b/code/espurna/system.ino new file mode 100644 index 00000000..e437bccc --- /dev/null +++ b/code/espurna/system.ino @@ -0,0 +1,170 @@ +/* + +SYSTEM MODULE + +Copyright (C) 2018 by Xose Pérez + +*/ + +#include + +// ----------------------------------------------------------------------------- + +unsigned long _loop_delay = 0; +bool _system_send_heartbeat = false; + +// Calculated load average 0 to 100; +unsigned short int _load_average = 100; + +// ----------------------------------------------------------------------------- + +#if SYSTEM_CHECK_ENABLED + +// Call this method on boot with start=true to increase the crash counter +// Call it again once the system is stable to decrease the counter +// If the counter reaches SYSTEM_CHECK_MAX then the system is flagged as unstable +// setting _systemOK = false; +// +// An unstable system will only have serial access, WiFi in AP mode and OTA + +bool _systemStable = true; + +void systemCheck(bool stable) { + unsigned char value = EEPROMr.read(EEPROM_CRASH_COUNTER); + if (stable) { + value = 0; + DEBUG_MSG_P(PSTR("[MAIN] System OK\n")); + } else { + if (++value > SYSTEM_CHECK_MAX) { + _systemStable = false; + value = 0; + DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n")); + } + } + EEPROMr.write(EEPROM_CRASH_COUNTER, value); + EEPROMr.commit(); +} + +bool systemCheck() { + return _systemStable; +} + +void systemCheckLoop() { + static bool checked = false; + if (!checked && (millis() > SYSTEM_CHECK_TIME)) { + // Check system as stable + systemCheck(true); + checked = true; + } +} + +#endif + +// ----------------------------------------------------------------------------- + +void systemSendHeartbeat() { + _system_send_heartbeat = true; +} + +unsigned long systemLoopDelay() { + return _loop_delay; +} + + +unsigned long systemLoadAverage() { + return _load_average; +} + +void systemLoop() { + + // ------------------------------------------------------------------------- + // Check system stability + // ------------------------------------------------------------------------- + + #if SYSTEM_CHECK_ENABLED + systemCheckLoop(); + #endif + + // ------------------------------------------------------------------------- + // Heartbeat + // ------------------------------------------------------------------------- + + #if HEARTBEAT_ENABLED + // Heartbeat + static unsigned long last_hbeat = 0; + if (_system_send_heartbeat || (last_hbeat == 0) || (millis() - last_hbeat > HEARTBEAT_INTERVAL)) { + _system_send_heartbeat = false; + last_hbeat = millis(); + heartbeat(); + } + #endif // HEARTBEAT_ENABLED + + // ------------------------------------------------------------------------- + // Load Average calculation + // ------------------------------------------------------------------------- + + static unsigned long last_loadcheck = 0; + static unsigned long load_counter_temp = 0; + load_counter_temp++; + + if (millis() - last_loadcheck > LOADAVG_INTERVAL) { + + static unsigned long load_counter = 0; + static unsigned long load_counter_max = 1; + + load_counter = load_counter_temp; + load_counter_temp = 0; + if (load_counter > load_counter_max) { + load_counter_max = load_counter; + } + _load_average = 100 - (100 * load_counter / load_counter_max); + last_loadcheck = millis(); + + } + + // ------------------------------------------------------------------------- + // Power saving delay + // ------------------------------------------------------------------------- + + delay(_loop_delay); + +} + +void _systemSetupSpecificHardware() { + + //The ESPLive has an ADC MUX which needs to be configured. + #if defined(MANCAVEMADE_ESPLIVE) + pinMode(16, OUTPUT); + digitalWrite(16, HIGH); //Defualt CT input (pin B, solder jumper B) + #endif + + // These devices use the hardware UART + // to communicate to secondary microcontrollers + #if defined(ITEAD_SONOFF_RFBRIDGE) || defined(ITEAD_SONOFF_DUAL) || defined(STM_RELAY) + Serial.begin(SERIAL_BAUDRATE); + #endif + +} + +void systemSetup() { + + #if SPIFFS_SUPPORT + SPIFFS.begin(); + #endif + + // Question system stability + #if SYSTEM_CHECK_ENABLED + systemCheck(false); + #endif + + // Init device-specific hardware + _systemSetupSpecificHardware(); + + // Cache loop delay value to speed things (recommended max 250ms) + _loop_delay = atol(getSetting("loopDelay", LOOP_DELAY_TIME).c_str()); + _loop_delay = constrain(_loop_delay, 0, 300); + + // Register Loop + espurnaRegisterLoop(systemLoop); + +} diff --git a/code/espurna/telnet.ino b/code/espurna/telnet.ino index c0b2f1b9..4f858ab4 100644 --- a/code/espurna/telnet.ino +++ b/code/espurna/telnet.ino @@ -2,7 +2,7 @@ TELNET MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez Parts of the code have been borrowed from Thomas Sarlandie's NetServer (https://github.com/sarfata/kbox-firmware/tree/master/src/esp) @@ -14,16 +14,25 @@ Parts of the code have been borrowed from Thomas Sarlandie's NetServer AsyncServer * _telnetServer; AsyncClient * _telnetClients[TELNET_MAX_CLIENTS]; +bool _telnetFirst = true; // ----------------------------------------------------------------------------- // Private methods // ----------------------------------------------------------------------------- +#if WEB_SUPPORT + +bool _telnetWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "telnet", 6) == 0); +} + void _telnetWebSocketOnSend(JsonObject& root) { root["telnetVisible"] = 1; root["telnetSTA"] = getSetting("telnetSTA", TELNET_STA).toInt() == 1; } +#endif + void _telnetDisconnect(unsigned char clientId) { _telnetClients[clientId]->free(); _telnetClients[clientId] = NULL; @@ -49,8 +58,23 @@ unsigned char _telnetWrite(void *data, size_t len) { void _telnetData(unsigned char clientId, void *data, size_t len) { + // Skip first message since it's always garbage + if (_telnetFirst) { + _telnetFirst = false; + return; + } + // Capture close connection char * p = (char *) data; + + // C-d is sent as two bytes (sometimes repeating) + if (len >= 2) { + if ((p[0] == 0xFF) && (p[1] == 0xEC)) { + _telnetClients[clientId]->close(true); + return; + } + } + if ((strncmp(p, "close", 5) == 0) || (strncmp(p, "quit", 4) == 0)) { _telnetClients[clientId]->close(); return; @@ -64,7 +88,14 @@ void _telnetData(unsigned char clientId, void *data, size_t len) { void _telnetNewClient(AsyncClient *client) { if (client->localIP() != WiFi.softAPIP()) { - bool telnetSTA = getSetting("telnetSTA", TELNET_STA).toInt() == 1; + + // Telnet is always available for the ESPurna Core image + #ifdef ESPURNA_CORE + bool telnetSTA = true; + #else + bool telnetSTA = getSetting("telnetSTA", TELNET_STA).toInt() == 1; + #endif + if (!telnetSTA) { DEBUG_MSG_P(PSTR("[TELNET] Rejecting - Only local connections\n")); client->onDisconnect([](void *s, AsyncClient *c) { @@ -74,6 +105,7 @@ void _telnetNewClient(AsyncClient *client) { client->close(true); return; } + } for (unsigned char i = 0; i < TELNET_MAX_CLIENTS; i++) { @@ -93,15 +125,25 @@ void _telnetNewClient(AsyncClient *client) { }, 0); client->onError([i](void *s, AsyncClient *c, int8_t error) { - DEBUG_MSG_P(PSTR("[TELNET] Error %s (%d) on client #%d\n"), c->errorToString(error), error, i); + DEBUG_MSG_P(PSTR("[TELNET] Error %s (%d) on client #%u\n"), c->errorToString(error), error, i); }, 0); client->onTimeout([i](void *s, AsyncClient *c, uint32_t time) { - DEBUG_MSG_P(PSTR("[TELNET] Timeout on client #%d at %i\n"), i, time); + DEBUG_MSG_P(PSTR("[TELNET] Timeout on client #%u at %lu\n"), i, time); c->close(); }, 0); - DEBUG_MSG_P(PSTR("[TELNET] Client #%d connected\n"), i); + DEBUG_MSG_P(PSTR("[TELNET] Client #%u connected\n"), i); + + // If there is no terminal support automatically dump info and crash data + #if TERMINAL_SUPPORT == 0 + info(); + wifiDebug(); + debugDumpCrashInfo(); + debugClearCrashInfo(); + #endif + + _telnetFirst = true; wifiReconnectCheck(); return; @@ -144,6 +186,7 @@ void telnetSetup() { #if WEB_SUPPORT wsOnSendRegister(_telnetWebSocketOnSend); + wsOnReceiveRegister(_telnetWebSocketOnReceive); #endif DEBUG_MSG_P(PSTR("[TELNET] Listening on port %d\n"), TELNET_PORT); diff --git a/code/espurna/thinkspeak.ino b/code/espurna/thinkspeak.ino new file mode 100644 index 00000000..04b0c85c --- /dev/null +++ b/code/espurna/thinkspeak.ino @@ -0,0 +1,285 @@ +/* + +THINGSPEAK MODULE + +Copyright (C) 2018 by Xose Pérez + +*/ + +#if THINGSPEAK_SUPPORT + +#if THINGSPEAK_USE_ASYNC +#include +AsyncClient * _tspk_client; +#else +#include +#endif + +const char THINGSPEAK_REQUEST_TEMPLATE[] PROGMEM = + "POST %s HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: ESPurna\r\n" + "Connection: close\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %d\r\n\r\n" + "%s\r\n"; + +bool _tspk_enabled = false; +char * _tspk_queue[8] = {NULL}; + +bool _tspk_flush = false; +unsigned long _tspk_last_flush = 0; + +// ----------------------------------------------------------------------------- + +#if WEB_SUPPORT + +bool _tspkWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "tspk", 4) == 0); +} + +void _tspkWebSocketOnSend(JsonObject& root) { + + unsigned char visible = 0; + + root["tspkEnabled"] = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1; + root["tspkKey"] = getSetting("tspkKey"); + + JsonArray& relays = root.createNestedArray("tspkRelays"); + for (byte i=0; i 0) visible = 1; + + #if SENSOR_SUPPORT + JsonArray& list = root.createNestedArray("tspkMagnitudes"); + for (byte i=0; i 0) visible = 1; + #endif + + root["tspkVisible"] = visible; + +} + +#endif + +void _tspkConfigure() { + _tspk_enabled = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1; + if (_tspk_enabled && (getSetting("tspkKey").length() == 0)) { + _tspk_enabled = false; + setSetting("tspkEnabled", 0); + } +} + +#if THINGSPEAK_USE_ASYNC + +void _tspkPost(String data) { + + if (_tspk_client == NULL) { + _tspk_client = new AsyncClient(); + } + + _tspk_client->onDisconnect([](void *s, AsyncClient *c) { + DEBUG_MSG_P(PSTR("[THINGSPEAK] Disconnected\n")); + _tspk_client->free(); + delete _tspk_client; + _tspk_client = NULL; + }, 0); + + _tspk_client->onTimeout([](void *s, AsyncClient *c, uint32_t time) { + _tspk_client->close(true); + }, 0); + + _tspk_client->onData([](void * arg, AsyncClient * c, void * response, size_t len) { + char * b = (char *) response; + b[len] = 0; + char * p = strstr((char *)response, "\r\n\r\n"); + unsigned int code = (p != NULL) ? atoi(&p[4]) : 0; + DEBUG_MSG_P(PSTR("[THINGSPEAK] Response value: %d\n"), code); + _tspk_client->close(true); + }, NULL); + + _tspk_client->onConnect([data](void * arg, AsyncClient * client) { + + DEBUG_MSG_P(PSTR("[THINGSPEAK] Connected to %s:%d\n"), THINGSPEAK_HOST, THINGSPEAK_PORT); + + #if THINGSPEAK_USE_SSL + uint8_t fp[20] = {0}; + sslFingerPrintArray(THINGSPEAK_FINGERPRINT, fp); + SSL * ssl = _tspk_client->getSSL(); + if (ssl_match_fingerprint(ssl, fp) != SSL_OK) { + DEBUG_MSG_P(PSTR("[THINGSPEAK] Warning: certificate doesn't match\n")); + } + #endif + + DEBUG_MSG_P(PSTR("[THINGSPEAK] POST %s\n"), data.c_str()); + + char buffer[strlen_P(THINGSPEAK_REQUEST_TEMPLATE) + strlen(THINGSPEAK_URL) + strlen(THINGSPEAK_HOST) + data.length()]; + snprintf_P(buffer, sizeof(buffer), + THINGSPEAK_REQUEST_TEMPLATE, + THINGSPEAK_URL, + THINGSPEAK_HOST, + data.length(), + data.c_str() + ); + + client->write(buffer); + + }, NULL); + + #if ASYNC_TCP_SSL_ENABLED + bool connected = _tspk_client->connect(THINGSPEAK_HOST, THINGSPEAK_PORT, THINGSPEAK_USE_SSL); + #else + bool connected = _tspk_client->connect(THINGSPEAK_HOST, THINGSPEAK_PORT); + #endif + + if (!connected) { + DEBUG_MSG_P(PSTR("[THINGSPEAK] Connection failed\n")); + _tspk_client->close(true); + } + +} + +#else // THINGSPEAK_USE_ASYNC + +void _tspkPost(String data) { + + #if THINGSPEAK_USE_SSL + WiFiClientSecure _tspk_client; + #else + WiFiClient _tspk_client; + #endif + + if (_tspk_client.connect(THINGSPEAK_HOST, THINGSPEAK_PORT)) { + + DEBUG_MSG_P(PSTR("[THINGSPEAK] Connected to %s:%d\n"), THINGSPEAK_HOST, THINGSPEAK_PORT); + + if (!_tspk_client.verify(THINGSPEAK_FINGERPRINT, THINGSPEAK_HOST)) { + DEBUG_MSG_P(PSTR("[THINGSPEAK] Warning: certificate doesn't match\n")); + } + + DEBUG_MSG_P(PSTR("[THINGSPEAK] POST %s\n"), data.c_str()); + char buffer[strlen_P(THINGSPEAK_REQUEST_TEMPLATE) + strlen(THINGSPEAK_URL) + strlen(THINGSPEAK_HOST) + data.length()]; + snprintf_P(buffer, sizeof(buffer), + THINGSPEAK_REQUEST_TEMPLATE, + THINGSPEAK_URL, + THINGSPEAK_HOST, + data.length(), + data.c_str() + ); + _tspk_client.print(buffer); + + nice_delay(100); + + String response = _tspk_client.readString(); + int pos = response.indexOf("\r\n\r\n"); + unsigned int code = (pos > 0) ? response.substring(pos + 4).toInt() : 0; + DEBUG_MSG_P(PSTR("[THINGSPEAK] Response value: %d\n"), code); + _tspk_client.stop(); + return; + + } + + DEBUG_MSG_P(PSTR("[THINGSPEAK] Connection failed\n")); + +} + +#endif // THINGSPEAK_USE_ASYNC + +void _tspkEnqueue(unsigned char index, char * payload) { + DEBUG_MSG_P(PSTR("[THINGSPEAK] Enqueuing field #%d with value %s\n"), index, payload); + --index; + if (_tspk_queue[index] != NULL) free(_tspk_queue[index]); + _tspk_queue[index] = strdup(payload); +} + +void _tspkFlush() { + + String data; + + // Walk the fields + for (unsigned char id=0; id<8; id++) { + if (_tspk_queue[id] != NULL) { + if (data.length() > 0) data = data + String("&"); + data = data + String("field") + String(id+1) + String("=") + String(_tspk_queue[id]); + free(_tspk_queue[id]); + _tspk_queue[id] = NULL; + } + } + + // POST data if any + if (data.length() > 0) { + data = data + String("&api_key=") + getSetting("tspkKey"); + _tspkPost(data); + _tspk_last_flush = millis(); + } + +} +// ----------------------------------------------------------------------------- + +bool tspkEnqueueRelay(unsigned char index, unsigned char status) { + if (!_tspk_enabled) return true; + unsigned char id = getSetting("tspkRelay", index, 0).toInt(); + if (id > 0) { + char payload[3] = {0}; + itoa(status ? 1 : 0, payload, 10); + _tspkEnqueue(id, payload); + return true; + } + return false; +} + +bool tspkEnqueueMeasurement(unsigned char index, char * payload) { + if (!_tspk_enabled) return true; + unsigned char id = getSetting("tspkMagnitude", index, 0).toInt(); + if (id > 0) { + _tspkEnqueue(id, payload); + return true; + } + return false; +} + +void tspkFlush() { + _tspk_flush = true; +} + +bool tspkEnabled() { + return _tspk_enabled; +} + +void tspkSetup() { + + _tspkConfigure(); + + #if WEB_SUPPORT + wsOnSendRegister(_tspkWebSocketOnSend); + wsOnAfterParseRegister(_tspkConfigure); + wsOnReceiveRegister(_tspkWebSocketOnReceive); + #endif + + DEBUG_MSG_P(PSTR("[THINGSPEAK] Async %s, SSL %s\n"), + THINGSPEAK_USE_ASYNC ? "ENABLED" : "DISABLED", + THINGSPEAK_USE_SSL ? "ENABLED" : "DISABLED" + ); + + // Register loop + espurnaRegisterLoop(tspkLoop); + +} + +void tspkLoop() { + if (!_tspk_enabled) return; + if (!wifiConnected() || (WiFi.getMode() != WIFI_STA)) return; + if (_tspk_flush && (millis() - _tspk_last_flush > THINGSPEAK_MIN_INTERVAL)) { + _tspkFlush(); + _tspk_flush = false; + } +} + +#endif diff --git a/code/espurna/uartmqtt.ino b/code/espurna/uartmqtt.ino new file mode 100644 index 00000000..ed3132e6 --- /dev/null +++ b/code/espurna/uartmqtt.ino @@ -0,0 +1,105 @@ +/* + +UART_MQTT MODULE + +Copyright (C) 2018 by Albert Weterings +Adapted by Xose Pérez + +*/ + +#if UART_MQTT_SUPPORT + +char _uartmqttBuffer[UART_MQTT_BUFFER_SIZE]; +bool _uartmqttNewData = false; + +#if UART_MQTT_USE_SOFT + #include + SoftwareSerial _uart_mqtt_serial(UART_MQTT_RX_PIN, UART_MQTT_TX_PIN, false, UART_MQTT_BUFFER_SIZE); + #define UART_MQTT_PORT _uart_mqtt_serial +#else + #define UART_MQTT_PORT UART_MQTT_HW_PORT +#endif + +// ----------------------------------------------------------------------------- +// Private +// ----------------------------------------------------------------------------- + +void _uartmqttReceiveUART() { + + static unsigned char ndx = 0; + + while (UART_MQTT_PORT.available() > 0 && _uartmqttNewData == false) { + + char rc = UART_MQTT_PORT.read(); + + if (rc != UART_MQTT_TERMINATION) { + + _uartmqttBuffer[ndx] = rc; + if (ndx < UART_MQTT_BUFFER_SIZE - 1) ndx++; + + } else { + + _uartmqttBuffer[ndx] = '\0'; + _uartmqttNewData = true; + ndx = 0; + + } + + } + +} + +void _uartmqttSendMQTT() { + if (_uartmqttNewData == true && MQTT_SUPPORT) { + DEBUG_MSG_P(PSTR("[UART_MQTT] Send data over MQTT: %s\n"), _uartmqttBuffer); + mqttSend(MQTT_TOPIC_UARTIN, _uartmqttBuffer); + _uartmqttNewData = false; + } +} + +void _uartmqttSendUART(const char * message) { + DEBUG_MSG_P(PSTR("[UART_MQTT] Send data over UART: %s\n"), message); + UART_MQTT_PORT.println(message); +} + +void _uartmqttMQTTCallback(unsigned int type, const char * topic, const char * payload) { + + if (type == MQTT_CONNECT_EVENT) { + mqttSubscribe(MQTT_TOPIC_UARTOUT); + } + + if (type == MQTT_MESSAGE_EVENT) { + + // Match topic + String t = mqttMagnitude((char *) topic); + if (t.equals(MQTT_TOPIC_UARTOUT)) { + _uartmqttSendUART(payload); + } + + } + +} + +// ----------------------------------------------------------------------------- +// SETUP & LOOP +// ----------------------------------------------------------------------------- + +void _uartmqttLoop() { + _uartmqttReceiveUART(); + _uartmqttSendMQTT(); +} + +void uartmqttSetup() { + + // Init port + UART_MQTT_PORT.begin(UART_MQTT_BAUDRATE); + + // Register MQTT callbackj + mqttRegister(_uartmqttMQTTCallback); + + // Register loop + espurnaRegisterLoop(_uartmqttLoop); + +} + +#endif // UART_MQTT_SUPPORT diff --git a/code/espurna/utils.ino b/code/espurna/utils.ino index 6eec91ec..9a229c4a 100644 --- a/code/espurna/utils.ino +++ b/code/espurna/utils.ino @@ -2,7 +2,7 @@ UTILS MODULE -Copyright (C) 2017 by Xose Pérez +Copyright (C) 2017-2018 by Xose Pérez */ @@ -11,10 +11,28 @@ Ticker _defer_reset; String getIdentifier() { char buffer[20]; - snprintf_P(buffer, sizeof(buffer), PSTR("ESPURNA_%06X"), ESP.getChipId()); + snprintf_P(buffer, sizeof(buffer), PSTR("%s-%06X"), APP_NAME, ESP.getChipId()); return String(buffer); } +void setDefaultHostname() { + if (strlen(HOSTNAME) > 0) { + setSetting("hostname", HOSTNAME); + } else { + setSetting("hostname", getIdentifier()); + } +} + +void setBoardName() { + #ifndef ESPURNA_CORE + setSetting("boardName", DEVICE_NAME); + #endif +} + +String getBoardName() { + return getSetting("boardName", DEVICE_NAME); +} + String getCoreVersion() { String version = ESP.getCoreVersion(); #ifdef ARDUINO_ESP8266_RELEASE @@ -22,6 +40,7 @@ String getCoreVersion() { version = String(ARDUINO_ESP8266_RELEASE); } #endif + version.replace("_", "."); return version; } @@ -33,6 +52,10 @@ String getCoreRevision() { #endif } +unsigned long maxSketchSpace() { + return (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; +} + // WTF // Calling ESP.getFreeHeap() is making the system crash on a specific // AiLight bulb, but anywhere else... @@ -41,6 +64,16 @@ unsigned int getFreeHeap() { return ESP.getFreeHeap(); } +String getEspurnaModules() { + return FPSTR(espurna_modules); +} + +#if SENSOR_SUPPORT +String getEspurnaSensors() { + return FPSTR(espurna_sensors); +} +#endif + String buildTime() { const char time_now[] = __TIME__; // hh:mm:ss @@ -84,60 +117,14 @@ unsigned long getUptime() { } +#if HEARTBEAT_ENABLED + void heartbeat() { unsigned long uptime_seconds = getUptime(); unsigned int free_heap = getFreeHeap(); - // ------------------------------------------------------------------------- - // MQTT - // ------------------------------------------------------------------------- - #if MQTT_SUPPORT - #if (HEARTBEAT_REPORT_INTERVAL) - mqttSend(MQTT_TOPIC_INTERVAL, HEARTBEAT_INTERVAL / 1000); - #endif - #if (HEARTBEAT_REPORT_APP) - mqttSend(MQTT_TOPIC_APP, APP_NAME); - #endif - #if (HEARTBEAT_REPORT_VERSION) - mqttSend(MQTT_TOPIC_VERSION, APP_VERSION); - #endif - #if (HEARTBEAT_REPORT_HOSTNAME) - mqttSend(MQTT_TOPIC_HOSTNAME, getSetting("hostname").c_str()); - #endif - #if (HEARTBEAT_REPORT_IP) - mqttSend(MQTT_TOPIC_IP, getIP().c_str()); - #endif - #if (HEARTBEAT_REPORT_MAC) - mqttSend(MQTT_TOPIC_MAC, WiFi.macAddress().c_str()); - #endif - #if (HEARTBEAT_REPORT_RSSI) - mqttSend(MQTT_TOPIC_RSSI, String(WiFi.RSSI()).c_str()); - #endif - #if (HEARTBEAT_REPORT_UPTIME) - mqttSend(MQTT_TOPIC_UPTIME, String(uptime_seconds).c_str()); - #endif - #if (HEARTBEAT_REPORT_DATETIME) & (NTP_SUPPORT) - mqttSend(MQTT_TOPIC_DATETIME, String(ntpDateTime()).c_str()); - #endif - #if (HEARTBEAT_REPORT_FREEHEAP) - mqttSend(MQTT_TOPIC_FREEHEAP, String(free_heap).c_str()); - #endif - #if (HEARTBEAT_REPORT_RELAY) - relayMQTT(); - #endif - #if (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE) & (HEARTBEAT_REPORT_LIGHT) - lightMQTT(); - #endif - #if (HEARTBEAT_REPORT_VCC) - #if ADC_VCC_ENABLED - mqttSend(MQTT_TOPIC_VCC, String(ESP.getVcc()).c_str()); - #endif - #endif - #if (HEARTBEAT_REPORT_STATUS) - mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); - #endif bool serial = !mqttConnected(); #else bool serial = true; @@ -148,14 +135,73 @@ void heartbeat() { // ------------------------------------------------------------------------- if (serial) { - DEBUG_MSG_P(PSTR("[MAIN] Uptime: %ld seconds\n"), uptime_seconds); - DEBUG_MSG_P(PSTR("[MAIN] Free heap: %d bytes\n"), free_heap); - #if ADC_VCC_ENABLED - DEBUG_MSG_P(PSTR("[MAIN] Power: %d mV\n"), ESP.getVcc()); + DEBUG_MSG_P(PSTR("[MAIN] Uptime: %lu seconds\n"), uptime_seconds); + DEBUG_MSG_P(PSTR("[MAIN] Free heap: %lu bytes\n"), free_heap); + #if ADC_MODE_VALUE == ADC_VCC + DEBUG_MSG_P(PSTR("[MAIN] Power: %lu mV\n"), ESP.getVcc()); + #endif + #if NTP_SUPPORT + if (ntpSynced()) DEBUG_MSG_P(PSTR("[MAIN] Time: %s\n"), (char *) ntpDateTime().c_str()); #endif } - #if NTP_SUPPORT - DEBUG_MSG_P(PSTR("[MAIN] Time: %s\n"), (char *) ntpDateTime().c_str()); + + // ------------------------------------------------------------------------- + // MQTT + // ------------------------------------------------------------------------- + + #if MQTT_SUPPORT + if (!serial) { + #if (HEARTBEAT_REPORT_INTERVAL) + mqttSend(MQTT_TOPIC_INTERVAL, HEARTBEAT_INTERVAL / 1000); + #endif + #if (HEARTBEAT_REPORT_APP) + mqttSend(MQTT_TOPIC_APP, APP_NAME); + #endif + #if (HEARTBEAT_REPORT_VERSION) + mqttSend(MQTT_TOPIC_VERSION, APP_VERSION); + #endif + #if (HEARTBEAT_REPORT_BOARD) + mqttSend(MQTT_TOPIC_BOARD, getBoardName().c_str()); + #endif + #if (HEARTBEAT_REPORT_HOSTNAME) + mqttSend(MQTT_TOPIC_HOSTNAME, getSetting("hostname").c_str()); + #endif + #if (HEARTBEAT_REPORT_IP) + mqttSend(MQTT_TOPIC_IP, getIP().c_str()); + #endif + #if (HEARTBEAT_REPORT_MAC) + mqttSend(MQTT_TOPIC_MAC, WiFi.macAddress().c_str()); + #endif + #if (HEARTBEAT_REPORT_RSSI) + mqttSend(MQTT_TOPIC_RSSI, String(WiFi.RSSI()).c_str()); + #endif + #if (HEARTBEAT_REPORT_UPTIME) + mqttSend(MQTT_TOPIC_UPTIME, String(uptime_seconds).c_str()); + #endif + #if (HEARTBEAT_REPORT_DATETIME) && (NTP_SUPPORT) + if (ntpSynced()) mqttSend(MQTT_TOPIC_DATETIME, ntpDateTime().c_str()); + #endif + #if (HEARTBEAT_REPORT_FREEHEAP) + mqttSend(MQTT_TOPIC_FREEHEAP, String(free_heap).c_str()); + #endif + #if (HEARTBEAT_REPORT_RELAY) + relayMQTT(); + #endif + #if (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE) & (HEARTBEAT_REPORT_LIGHT) + lightMQTT(); + #endif + #if (HEARTBEAT_REPORT_VCC) + #if ADC_MODE_VALUE == ADC_VCC + mqttSend(MQTT_TOPIC_VCC, String(ESP.getVcc()).c_str()); + #endif + #endif + #if (HEARTBEAT_REPORT_STATUS) + mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); + #endif + #if (LOADAVG_REPORT) + mqttSend(MQTT_TOPIC_LOADAVG, String(systemLoadAverage()).c_str()); + #endif + } #endif // ------------------------------------------------------------------------- @@ -171,32 +217,185 @@ void heartbeat() { #endif #endif +} + +#endif /// HEARTBEAT_ENABLED + +// ----------------------------------------------------------------------------- +// INFO +// ----------------------------------------------------------------------------- + +extern "C" uint32_t _SPIFFS_start; +extern "C" uint32_t _SPIFFS_end; + +unsigned int info_bytes2sectors(size_t size) { + return (int) (size + SPI_FLASH_SEC_SIZE - 1) / SPI_FLASH_SEC_SIZE; +} + +unsigned long info_ota_space() { + return (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; +} + +unsigned long info_filesystem_space() { + return ((uint32_t)&_SPIFFS_end - (uint32_t)&_SPIFFS_start); +} + +unsigned long info_eeprom_space() { + return EEPROMr.reserved() * SPI_FLASH_SEC_SIZE; +} + +void _info_print_memory_layout_line(const char * name, unsigned long bytes, bool reset) { + static unsigned long index = 0; + if (reset) index = 0; + if (0 == bytes) return; + unsigned int _sectors = info_bytes2sectors(bytes); + DEBUG_MSG_P(PSTR("[INIT] %-20s: %8lu bytes / %4d sectors (%4d to %4d)\n"), name, bytes, _sectors, index, index + _sectors - 1); + index += _sectors; +} + +void _info_print_memory_layout_line(const char * name, unsigned long bytes) { + _info_print_memory_layout_line(name, bytes, false); +} + +void info() { + + DEBUG_MSG_P(PSTR("\n\n")); + DEBUG_MSG_P(PSTR("[INIT] %s %s\n"), (char *) APP_NAME, (char *) APP_VERSION); + DEBUG_MSG_P(PSTR("[INIT] %s\n"), (char *) APP_AUTHOR); + DEBUG_MSG_P(PSTR("[INIT] %s\n\n"), (char *) APP_WEBSITE); + DEBUG_MSG_P(PSTR("[INIT] CPU chip ID: 0x%06X\n"), ESP.getChipId()); + DEBUG_MSG_P(PSTR("[INIT] CPU frequency: %u MHz\n"), ESP.getCpuFreqMHz()); + DEBUG_MSG_P(PSTR("[INIT] SDK version: %s\n"), ESP.getSdkVersion()); + DEBUG_MSG_P(PSTR("[INIT] Core version: %s\n"), getCoreVersion().c_str()); + DEBUG_MSG_P(PSTR("[INIT] Core revision: %s\n"), getCoreRevision().c_str()); + DEBUG_MSG_P(PSTR("\n")); + + // ------------------------------------------------------------------------- + + FlashMode_t mode = ESP.getFlashChipMode(); + DEBUG_MSG_P(PSTR("[INIT] Flash chip ID: 0x%06X\n"), ESP.getFlashChipId()); + DEBUG_MSG_P(PSTR("[INIT] Flash speed: %u Hz\n"), ESP.getFlashChipSpeed()); + DEBUG_MSG_P(PSTR("[INIT] Flash mode: %s\n"), mode == FM_QIO ? "QIO" : mode == FM_QOUT ? "QOUT" : mode == FM_DIO ? "DIO" : mode == FM_DOUT ? "DOUT" : "UNKNOWN"); + DEBUG_MSG_P(PSTR("\n")); + + _info_print_memory_layout_line("Flash size (CHIP)", ESP.getFlashChipRealSize(), true); + _info_print_memory_layout_line("Flash size (SDK)", ESP.getFlashChipSize(), true); + _info_print_memory_layout_line("Reserved", 1 * SPI_FLASH_SEC_SIZE, true); + _info_print_memory_layout_line("Firmware size", ESP.getSketchSize()); + _info_print_memory_layout_line("Max OTA size", info_ota_space()); + _info_print_memory_layout_line("SPIFFS size", info_filesystem_space()); + _info_print_memory_layout_line("EEPROM size", info_eeprom_space()); + _info_print_memory_layout_line("Reserved", 4 * SPI_FLASH_SEC_SIZE); + DEBUG_MSG_P(PSTR("\n")); + + DEBUG_MSG_P(PSTR("[INIT] EEPROM sectors: %s\n"), (char *) eepromSectors().c_str()); + DEBUG_MSG_P(PSTR("\n")); + + // ------------------------------------------------------------------------- + + #if SPIFFS_SUPPORT + FSInfo fs_info; + bool fs = SPIFFS.info(fs_info); + if (fs) { + DEBUG_MSG_P(PSTR("[INIT] SPIFFS total size: %8u bytes / %4d sectors\n"), fs_info.totalBytes, sectors(fs_info.totalBytes)); + DEBUG_MSG_P(PSTR("[INIT] used size: %8u bytes\n"), fs_info.usedBytes); + DEBUG_MSG_P(PSTR("[INIT] block size: %8u bytes\n"), fs_info.blockSize); + DEBUG_MSG_P(PSTR("[INIT] page size: %8u bytes\n"), fs_info.pageSize); + DEBUG_MSG_P(PSTR("[INIT] max files: %8u\n"), fs_info.maxOpenFiles); + DEBUG_MSG_P(PSTR("[INIT] max length: %8u\n"), fs_info.maxPathLength); + } else { + DEBUG_MSG_P(PSTR("[INIT] No SPIFFS partition\n")); + } + DEBUG_MSG_P(PSTR("\n")); + #endif + // ------------------------------------------------------------------------- - // WebSockets + + DEBUG_MSG_P(PSTR("[INIT] BOARD: %s\n"), getBoardName().c_str()); + DEBUG_MSG_P(PSTR("[INIT] SUPPORT: %s\n"), getEspurnaModules().c_str()); + #if SENSOR_SUPPORT + DEBUG_MSG_P(PSTR("[INIT] SENSORS: %s\n"), getEspurnaSensors().c_str()); + #endif // SENSOR_SUPPORT + DEBUG_MSG_P(PSTR("\n")); + // ------------------------------------------------------------------------- - #if WEB_SUPPORT - #if NTP_SUPPORT - { - char buffer[200]; - snprintf_P( - buffer, - sizeof(buffer) - 1, - PSTR("{\"time\": \"%s\", \"uptime\": %lu, \"heap\": %lu}"), - ntpDateTime().c_str(), uptime_seconds, free_heap - ); - wsSend(buffer); + + unsigned char reason = resetReason(); + if (reason > 0) { + char buffer[32]; + strcpy_P(buffer, custom_reset_string[reason-1]); + DEBUG_MSG_P(PSTR("[INIT] Last reset reason: %s\n"), buffer); + } else { + DEBUG_MSG_P(PSTR("[INIT] Last reset reason: %s\n"), (char *) ESP.getResetReason().c_str()); } + + DEBUG_MSG_P(PSTR("[INIT] Settings size: %u bytes\n"), settingsSize()); + DEBUG_MSG_P(PSTR("[INIT] Free heap: %u bytes\n"), getFreeHeap()); + #if ADC_MODE_VALUE == ADC_VCC + DEBUG_MSG_P(PSTR("[INIT] Power: %u mV\n"), ESP.getVcc()); #endif + + DEBUG_MSG_P(PSTR("[INIT] Power saving delay value: %lu ms\n"), systemLoopDelay()); + + #if SYSTEM_CHECK_ENABLED + if (!systemCheck()) DEBUG_MSG_P(PSTR("\n[INIT] Device is in SAFE MODE\n")); #endif + DEBUG_MSG_P(PSTR("\n")); + } +// ----------------------------------------------------------------------------- +// SSL +// ----------------------------------------------------------------------------- + +#if ASYNC_TCP_SSL_ENABLED + +bool sslCheckFingerPrint(const char * fingerprint) { + return (strlen(fingerprint) == 59); +} + +bool sslFingerPrintArray(const char * fingerprint, unsigned char * bytearray) { + + // check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59) + if (!sslCheckFingerPrint(fingerprint)) return false; + + // walk the fingerprint + for (unsigned int i=0; i<20; i++) { + bytearray[i] = strtol(fingerprint + 3*i, NULL, 16); + } + + return true; + +} + +bool sslFingerPrintChar(const char * fingerprint, char * destination) { + + // check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59) + if (!sslCheckFingerPrint(fingerprint)) return false; + + // copy it + strncpy(destination, fingerprint, 59); + + // walk the fingerprint replacing ':' for ' ' + for (unsigned char i = 0; i<59; i++) { + if (destination[i] == ':') destination[i] = ' '; + } + + return true; + +} + +#endif + +// ----------------------------------------------------------------------------- +// Reset // ----------------------------------------------------------------------------- unsigned char resetReason() { static unsigned char status = 255; if (status == 255) { - status = EEPROM.read(EEPROM_CUSTOM_RESET); + status = EEPROMr.read(EEPROM_CUSTOM_RESET); if (status > 0) resetReason(0); if (status > CUSTOM_RESET_MAX) status = 0; } @@ -204,8 +403,8 @@ unsigned char resetReason() { } void resetReason(unsigned char reason) { - EEPROM.write(EEPROM_CUSTOM_RESET, reason); - EEPROM.commit(); + EEPROMr.write(EEPROM_CUSTOM_RESET, reason); + EEPROMr.commit(); } void reset(unsigned char reason) { @@ -219,50 +418,6 @@ void deferredReset(unsigned long delay, unsigned char reason) { // ----------------------------------------------------------------------------- -#if SYSTEM_CHECK_ENABLED - -// Call this method on boot with start=true to increase the crash counter -// Call it again once the system is stable to decrease the counter -// If the counter reaches SYSTEM_CHECK_MAX then the system is flagged as unstable -// setting _systemOK = false; -// -// An unstable system will only have serial access, WiFi in AP mode and OTA - -bool _systemStable = true; - -void systemCheck(bool stable) { - unsigned char value = EEPROM.read(EEPROM_CRASH_COUNTER); - if (stable) { - value = 0; - DEBUG_MSG_P(PSTR("[MAIN] System OK\n")); - } else { - if (++value > SYSTEM_CHECK_MAX) { - _systemStable = false; - value = 0; - DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n")); - } - } - EEPROM.write(EEPROM_CRASH_COUNTER, value); - EEPROM.commit(); -} - -bool systemCheck() { - return _systemStable; -} - -void systemCheckLoop() { - static bool checked = false; - if (!checked && (millis() > SYSTEM_CHECK_TIME)) { - // Check system as stable - systemCheck(true); - checked = true; - } -} - -#endif - -// ----------------------------------------------------------------------------- - char * ltrim(char * s) { char *p = s; while ((unsigned char) *p == ' ') ++p; @@ -279,3 +434,24 @@ void nice_delay(unsigned long ms) { unsigned long start = millis(); while (millis() - start < ms) delay(1); } + +// This method is called by the SDK to know where to connect the ADC +int __get_adc_mode() { + return (int) (ADC_MODE_VALUE); +} + +bool isNumber(const char * s) { + unsigned char len = strlen(s); + bool decimal = false; + for (unsigned char i=0; i0) return false; + } else if (s[i] == '.') { + if (decimal) return false; + decimal = true; + } else if (!isdigit(s[i])) { + return false; + } + } + return true; +} diff --git a/code/espurna/web.ino b/code/espurna/web.ino index 43de5ea3..29d9b351 100644 --- a/code/espurna/web.ino +++ b/code/espurna/web.ino @@ -2,7 +2,7 @@ WEBSERVER MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -43,32 +43,35 @@ void _onReset(AsyncWebServerRequest *request) { void _onGetConfig(AsyncWebServerRequest *request) { webLog(request); - if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str()); + if (!webAuthenticate(request)) { + return request->requestAuthentication(getSetting("hostname").c_str()); + } - AsyncJsonResponse * response = new AsyncJsonResponse(); - JsonObject& root = response->getRoot(); + AsyncResponseStream *response = request->beginResponseStream("text/json"); + DynamicJsonBuffer jsonBuffer; + JsonObject &root = jsonBuffer.createObject(); root["app"] = APP_NAME; root["version"] = APP_VERSION; - - unsigned int size = settingsKeyCount(); - for (unsigned int i=0; iaddHeader("Content-Disposition", buffer); - response->setLength(); + response->addHeader("X-XSS-Protection", "1; mode=block"); + response->addHeader("X-Content-Type-Options", "nosniff"); + response->addHeader("X-Frame-Options", "deny"); request->send(response); } void _onPostConfig(AsyncWebServerRequest *request) { webLog(request); - if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str()); + if (!webAuthenticate(request)) { + return request->requestAuthentication(getSetting("hostname").c_str()); + } request->send(_webConfigSuccess ? 200 : 400); } @@ -78,7 +81,7 @@ void _onPostConfigData(AsyncWebServerRequest *request, String filename, size_t i if (final && (index == 0)) { DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.parseObject((char *) data); - if (root.success()) _webConfigSuccess = settingsRestore(root); + if (root.success()) _webConfigSuccess = settingsRestoreJson(root); return; } @@ -105,7 +108,7 @@ void _onPostConfigData(AsyncWebServerRequest *request, String filename, size_t i // Parse JSON DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.parseObject((char *) _webConfigBuffer->data()); - if (root.success()) _webConfigSuccess = settingsRestore(root); + if (root.success()) _webConfigSuccess = settingsRestoreJson(root); delete _webConfigBuffer; } @@ -116,7 +119,9 @@ void _onPostConfigData(AsyncWebServerRequest *request, String filename, size_t i void _onHome(AsyncWebServerRequest *request) { webLog(request); - if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str()); + if (!webAuthenticate(request)) { + return request->requestAuthentication(getSetting("hostname").c_str()); + } if (request->header("If-Modified-Since").equals(_last_modified)) { @@ -155,6 +160,9 @@ void _onHome(AsyncWebServerRequest *request) { response->addHeader("Content-Encoding", "gzip"); response->addHeader("Last-Modified", _last_modified); + response->addHeader("X-XSS-Protection", "1; mode=block"); + response->addHeader("X-Content-Type-Options", "nosniff"); + response->addHeader("X-Frame-Options", "deny"); request->send(response); } @@ -216,7 +224,9 @@ int _onCertificate(void * arg, const char *filename, uint8_t **buf) { void _onUpgrade(AsyncWebServerRequest *request) { webLog(request); - if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str()); + if (!webAuthenticate(request)) { + return request->requestAuthentication(getSetting("hostname").c_str()); + } char buffer[10]; if (!Update.hasError()) { @@ -227,7 +237,12 @@ void _onUpgrade(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", buffer); response->addHeader("Connection", "close"); - if (!Update.hasError()) { + response->addHeader("X-XSS-Protection", "1; mode=block"); + response->addHeader("X-Content-Type-Options", "nosniff"); + response->addHeader("X-Frame-Options", "deny"); + if (Update.hasError()) { + eepromRotate(true); + } else { deferredReset(100, CUSTOM_RESET_UPGRADE); } request->send(response); @@ -235,7 +250,12 @@ void _onUpgrade(AsyncWebServerRequest *request) { } void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { + if (!index) { + + // Disabling EEPROM rotation to prevent writing to EEPROM after the upgrade + eepromRotate(false); + DEBUG_MSG_P(PSTR("[UPGRADE] Start: %s\n"), filename.c_str()); Update.runAsync(true); if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) { @@ -243,7 +263,9 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde Update.printError(DEBUG_PORT); #endif } + } + if (!Update.hasError()) { if (Update.write(data, len) != len) { #ifdef DEBUG_PORT @@ -251,6 +273,7 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde #endif } } + if (final) { if (Update.end(true)){ DEBUG_MSG_P(PSTR("[UPGRADE] Success: %u bytes\n"), index + len); @@ -266,11 +289,15 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde // ----------------------------------------------------------------------------- -bool _authenticate(AsyncWebServerRequest *request) { - String password = getSetting("adminPass", ADMIN_PASS); - char httpPassword[password.length() + 1]; - password.toCharArray(httpPassword, password.length() + 1); - return request->authenticate(WEB_USERNAME, httpPassword); +bool webAuthenticate(AsyncWebServerRequest *request) { + #if USE_PASSWORD + String password = getSetting("adminPass", ADMIN_PASS); + char httpPassword[password.length() + 1]; + password.toCharArray(httpPassword, password.length() + 1); + return request->authenticate(WEB_USERNAME, httpPassword); + #else + return true; + #endif } // ----------------------------------------------------------------------------- @@ -279,6 +306,14 @@ AsyncWebServer * webServer() { return _server; } +unsigned int webPort() { + #if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED + return 443; + #else + return getSetting("webPort", WEB_PORT).toInt(); + #endif +} + void webLog(AsyncWebServerRequest *request) { DEBUG_MSG_P(PSTR("[WEBSERVER] Request: %s %s\n"), request->methodToString(), request->url().c_str()); } @@ -289,11 +324,7 @@ void webSetup() { snprintf_P(_last_modified, sizeof(_last_modified), PSTR("%s %s GMT"), __DATE__, __TIME__); // Create server - #if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED - unsigned int port = 443; - #else - unsigned int port = getSetting("webPort", WEB_PORT).toInt(); - #endif + unsigned int port = webPort(); _server = new AsyncWebServer(port); // Rewrites @@ -325,12 +356,12 @@ void webSetup() { // Run server #if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED - _server->onSslFileRequest(_onCertificate, NULL); - _server->beginSecure("server.cer", "server.key", NULL); + _server->onSslFileRequest(_onCertificate, NULL); + _server->beginSecure("server.cer", "server.key", NULL); #else - _server->begin(); + _server->begin(); #endif - DEBUG_MSG_P(PSTR("[WEBSERVER] Webserver running on port %d\n"), port); + DEBUG_MSG_P(PSTR("[WEBSERVER] Webserver running on port %u\n"), port); } diff --git a/code/espurna/wifi.ino b/code/espurna/wifi.ino index 81a45442..37f55464 100644 --- a/code/espurna/wifi.ino +++ b/code/espurna/wifi.ino @@ -2,90 +2,56 @@ WIFI MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ #include "JustWifi.h" +#include + +uint32_t _wifi_scan_client_id = 0; +bool _wifi_wps_running = false; +bool _wifi_smartconfig_running = false; +uint8_t _wifi_ap_mode = WIFI_AP_FALLBACK; // ----------------------------------------------------------------------------- -// WIFI +// PRIVATE // ----------------------------------------------------------------------------- -void _wifiWebSocketOnSend(JsonObject& root) { - root["maxNetworks"] = WIFI_MAX_NETWORKS; - JsonArray& wifi = root.createNestedArray("wifi"); - for (byte i=0; i 0) && + (WiFi.softAPgetStationNum() == 0) + ) { + jw.enableAP(false); } - return WiFi.localIP().toString(); -} -String getNetwork() { - if (WiFi.getMode() == WIFI_AP) { - return jw.getAPSSID(); - } - return WiFi.SSID(); } -void wifiDisconnect() { - jw.disconnect(); -} - -void resetConnectionTimeout() { - jw.resetReconnectTimeout(); -} - -bool wifiConnected() { - return jw.connected(); -} - -bool createAP() { - jw.disconnect(); - jw.resetReconnectTimeout(); - return jw.createAP(); -} - -void wifiReconnectCheck() { - bool connected = false; - #if WEB_SUPPORT - if (wsConnected()) connected = true; - #endif - #if TELNET_SUPPORT - if (telnetConnected()) connected = true; - #endif - jw.setReconnectTimeout(connected ? 0 : WIFI_RECONNECT_INTERVAL); -} - -void wifiConfigure() { +void _wifiConfigure() { jw.setHostname(getSetting("hostname").c_str()); - jw.setSoftAP(getSetting("hostname").c_str(), getSetting("adminPass", ADMIN_PASS).c_str()); + #if USE_PASSWORD + jw.setSoftAP(getSetting("hostname").c_str(), getSetting("adminPass", ADMIN_PASS).c_str()); + #else + jw.setSoftAP(getSetting("hostname").c_str()); + #endif jw.setConnectTimeout(WIFI_CONNECT_TIMEOUT); wifiReconnectCheck(); - jw.setAPMode(WIFI_AP_MODE); + jw.enableAPFallback(true); jw.cleanNetworks(); + _wifi_ap_mode = getSetting("apmode", WIFI_AP_FALLBACK).toInt(); + // If system is flagged unstable we do not init wifi networks #if SYSTEM_CHECK_ENABLED if (!systemCheck()) return; #endif // Clean settings - wifiClean(WIFI_MAX_NETWORKS); + _wifiClean(WIFI_MAX_NETWORKS); int i; for (i = 0; i< WIFI_MAX_NETWORKS; i++) { @@ -107,46 +73,78 @@ void wifiConfigure() { } } - // Scan for best network only if we have more than 1 defined - jw.scanNetworks(i>1); + jw.enableScan(getSetting("wifiScan", WIFI_SCAN_NETWORKS).toInt() == 1); } -void wifiStatus() { +void _wifiScan(uint32_t client_id = 0) { + + DEBUG_MSG_P(PSTR("[WIFI] Start scanning\n")); - if (WiFi.getMode() == WIFI_AP_STA) { - DEBUG_MSG_P(PSTR("[WIFI] MODE AP + STA --------------------------------\n")); - } else if (WiFi.getMode() == WIFI_AP) { - DEBUG_MSG_P(PSTR("[WIFI] MODE AP --------------------------------------\n")); - } else if (WiFi.getMode() == WIFI_STA) { - DEBUG_MSG_P(PSTR("[WIFI] MODE STA -------------------------------------\n")); + #if WEB_SUPPORT + String output; + #endif + + unsigned char result = WiFi.scanNetworks(); + + if (result == WIFI_SCAN_FAILED) { + DEBUG_MSG_P(PSTR("[WIFI] Scan failed\n")); + #if WEB_SUPPORT + output = String("Failed scan"); + #endif + } else if (result == 0) { + DEBUG_MSG_P(PSTR("[WIFI] No networks found\n")); + #if WEB_SUPPORT + output = String("No networks found"); + #endif } else { - DEBUG_MSG_P(PSTR("[WIFI] MODE OFF -------------------------------------\n")); - DEBUG_MSG_P(PSTR("[WIFI] No connection\n")); - } - if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) { - DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), jw.getAPSSID().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] PASS %s\n"), getSetting("adminPass", ADMIN_PASS).c_str()); - DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.softAPIP().toString().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.softAPmacAddress().c_str()); - } + DEBUG_MSG_P(PSTR("[WIFI] %d networks found:\n"), result); + + // Populate defined networks with scan data + for (int8_t i = 0; i < result; ++i) { + + String ssid_scan; + int32_t rssi_scan; + uint8_t sec_scan; + uint8_t* BSSID_scan; + int32_t chan_scan; + bool hidden_scan; + char buffer[128]; + + WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan); + + snprintf_P(buffer, sizeof(buffer), + PSTR("BSSID: %02X:%02X:%02X:%02X:%02X:%02X SEC: %s RSSI: %3d CH: %2d SSID: %s"), + BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], BSSID_scan[6], + (sec_scan != ENC_TYPE_NONE ? "YES" : "NO "), + rssi_scan, + chan_scan, + (char *) ssid_scan.c_str() + ); + + DEBUG_MSG_P(PSTR("[WIFI] > %s\n"), buffer); + + #if WEB_SUPPORT + if (client_id > 0) output = output + String(buffer) + String("
"); + #endif + + } - if ((WiFi.getMode() & WIFI_STA) == WIFI_STA) { - DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), WiFi.SSID().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.localIP().toString().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.macAddress().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] DNS %s\n"), WiFi.dnsIP().toString().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] MASK %s\n"), WiFi.subnetMask().toString().c_str()); - DEBUG_MSG_P(PSTR("[WIFI] HOST %s\n"), WiFi.hostname().c_str()); } - DEBUG_MSG_P(PSTR("[WIFI] ----------------------------------------------\n")); + #if WEB_SUPPORT + if (client_id > 0) { + output = String("{\"scanResult\": \"") + output + String("\"}"); + wsSend(client_id, output.c_str()); + } + #endif + + WiFi.scanDelete(); } -bool wifiClean(unsigned char num) { +bool _wifiClean(unsigned char num) { bool changed = false; int i = 0; @@ -188,131 +186,463 @@ bool wifiClean(unsigned char num) { } // Inject hardcoded networks -void wifiInject() { +void _wifiInject() { - #ifdef WIFI1_SSID - if (getSetting("ssid", 0, "").length() == 0) setSetting("ssid", 0, WIFI1_SSID); - #endif - #ifdef WIFI1_PASS - if (getSetting("pass", 0, "").length() == 0) setSetting("pass", 0, WIFI1_PASS); - #endif - #ifdef WIFI1_IP - if (getSetting("ip", 0, "").length() == 0) setSetting("ip", 0, WIFI1_IP); - #endif - #ifdef WIFI1_GW - if (getSetting("gw", 0, "").length() == 0) setSetting("gw", 0, WIFI1_GW); - #endif - #ifdef WIFI1_MASK - if (getSetting("mask", 0, "").length() == 0) setSetting("mask", 0, WIFI1_MASK); - #endif - #ifdef WIFI1_DNS - if (getSetting("dns", 0, "").length() == 0) setSetting("dns", 0, WIFI1_DNS); - #endif + if (strlen(WIFI1_SSID)) { - #ifdef WIFI2_SSID - if (getSetting("ssid", 1, "").length() == 0) setSetting("ssid", 1, WIFI2_SSID); - #endif - #ifdef WIFI2_PASS - if (getSetting("pass", 1, "").length() == 0) setSetting("pass", 1, WIFI2_PASS); - #endif - #ifdef WIFI2_IP - if (getSetting("ip", 1, "").length() == 0) setSetting("ip", 1, WIFI2_IP); - #endif - #ifdef WIFI2_GW - if (getSetting("gw", 1, "").length() == 0) setSetting("gw", 1, WIFI2_GW); - #endif - #ifdef WIFI2_MASK - if (getSetting("mask", 1, "").length() == 0) setSetting("mask", 1, WIFI2_MASK); - #endif - #ifdef WIFI2_DNS - if (getSetting("dns", 1, "").length() == 0) setSetting("dns", 1, WIFI2_DNS); - #endif + if (!hasSetting("ssid", 0)) { + setSetting("ssid", 0, WIFI1_SSID); + setSetting("pass", 0, WIFI1_PASS); + setSetting("ip", 0, WIFI1_IP); + setSetting("gw", 0, WIFI1_GW); + setSetting("mask", 0, WIFI1_MASK); + setSetting("dns", 0, WIFI1_DNS); + } + + if (strlen(WIFI2_SSID)) { + if (!hasSetting("ssid", 1)) { + setSetting("ssid", 1, WIFI2_SSID); + setSetting("pass", 1, WIFI2_PASS); + setSetting("ip", 1, WIFI2_IP); + setSetting("gw", 1, WIFI2_GW); + setSetting("mask", 1, WIFI2_MASK); + setSetting("dns", 1, WIFI2_DNS); + } + } + } } -void wifiSetup() { +void _wifiCallback(justwifi_messages_t code, char * parameter) { - #if WIFI_SLEEP_ENABLED - wifi_set_sleep_type(LIGHT_SLEEP_T); - #endif + if (MESSAGE_WPS_START == code) { + _wifi_wps_running = true; + } - wifiInject(); - wifiConfigure(); + if (MESSAGE_SMARTCONFIG_START == code) { + _wifi_smartconfig_running = true; + } - // Message callbacks - jw.onMessage([](justwifi_messages_t code, char * parameter) { + if (MESSAGE_WPS_ERROR == code || MESSAGE_SMARTCONFIG_ERROR == code) { + _wifi_wps_running = false; + _wifi_smartconfig_running = false; + } + + if (MESSAGE_WPS_SUCCESS == code || MESSAGE_SMARTCONFIG_SUCCESS == code) { + + String ssid = WiFi.SSID(); + String pass = WiFi.psk(); + + // Look for the same SSID + uint8_t count = 0; + while (count < WIFI_MAX_NETWORKS) { + if (!hasSetting("ssid", count)) break; + if (ssid.equals(getSetting("ssid", count, ""))) break; + count++; + } + + // If we have reached the max we overwrite the first one + if (WIFI_MAX_NETWORKS == count) count = 0; + + setSetting("ssid", count, ssid); + setSetting("pass", count, pass); + + _wifi_wps_running = false; + _wifi_smartconfig_running = false; + + } + +} + +#if WIFI_AP_CAPTIVE + +#include "DNSServer.h" + +DNSServer _wifi_dnsServer; + +void _wifiCaptivePortal(justwifi_messages_t code, char * parameter) { + + if (MESSAGE_ACCESSPOINT_CREATED == code) { + _wifi_dnsServer.setErrorReplyCode(DNSReplyCode::NoError); + _wifi_dnsServer.start(53, "*", WiFi.softAPIP()); + DEBUG_MSG_P(PSTR("[WIFI] Captive portal enabled\n")); + } + + if (MESSAGE_CONNECTED == code) { + _wifi_dnsServer.stop(); + DEBUG_MSG_P(PSTR("[WIFI] Captive portal disabled\n")); + } + +} + +#endif // WIFI_AP_CAPTIVE + +#if DEBUG_SUPPORT + +void _wifiDebugCallback(justwifi_messages_t code, char * parameter) { + + // ------------------------------------------------------------------------- + + if (code == MESSAGE_SCANNING) { + DEBUG_MSG_P(PSTR("[WIFI] Scanning\n")); + } + + if (code == MESSAGE_SCAN_FAILED) { + DEBUG_MSG_P(PSTR("[WIFI] Scan failed\n")); + } + + if (code == MESSAGE_NO_NETWORKS) { + DEBUG_MSG_P(PSTR("[WIFI] No networks found\n")); + } + + if (code == MESSAGE_NO_KNOWN_NETWORKS) { + DEBUG_MSG_P(PSTR("[WIFI] No known networks found\n")); + } + + if (code == MESSAGE_FOUND_NETWORK) { + DEBUG_MSG_P(PSTR("[WIFI] %s\n"), parameter); + } + + // ------------------------------------------------------------------------- + + if (code == MESSAGE_CONNECTING) { + DEBUG_MSG_P(PSTR("[WIFI] Connecting to %s\n"), parameter); + } + + if (code == MESSAGE_CONNECT_WAITING) { + // too much noise + } + + if (code == MESSAGE_CONNECT_FAILED) { + DEBUG_MSG_P(PSTR("[WIFI] Could not connect to %s\n"), parameter); + } + + if (code == MESSAGE_CONNECTED) { + wifiDebug(WIFI_STA); + } + + if (code == MESSAGE_DISCONNECTED) { + DEBUG_MSG_P(PSTR("[WIFI] Disconnected\n")); + } - #if DEBUG_SUPPORT + // ------------------------------------------------------------------------- - if (code == MESSAGE_SCANNING) { - DEBUG_MSG_P(PSTR("[WIFI] Scanning\n")); - } + if (code == MESSAGE_ACCESSPOINT_CREATING) { + DEBUG_MSG_P(PSTR("[WIFI] Creating access point\n")); + } - if (code == MESSAGE_SCAN_FAILED) { - DEBUG_MSG_P(PSTR("[WIFI] Scan failed\n")); - } + if (code == MESSAGE_ACCESSPOINT_CREATED) { + wifiDebug(WIFI_AP); + } + + if (code == MESSAGE_ACCESSPOINT_FAILED) { + DEBUG_MSG_P(PSTR("[WIFI] Could not create access point\n")); + } - if (code == MESSAGE_NO_NETWORKS) { - DEBUG_MSG_P(PSTR("[WIFI] No networks found\n")); - } + if (code == MESSAGE_ACCESSPOINT_DESTROYED) { + DEBUG_MSG_P(PSTR("[WIFI] Access point destroyed\n")); + } + + // ------------------------------------------------------------------------- + + if (code == MESSAGE_WPS_START) { + DEBUG_MSG_P(PSTR("[WIFI] WPS started\n")); + } - if (code == MESSAGE_NO_KNOWN_NETWORKS) { - DEBUG_MSG_P(PSTR("[WIFI] No known networks found\n")); - } + if (code == MESSAGE_WPS_SUCCESS) { + DEBUG_MSG_P(PSTR("[WIFI] WPS succeded!\n")); + } - if (code == MESSAGE_FOUND_NETWORK) { - DEBUG_MSG_P(PSTR("[WIFI] %s\n"), parameter); - } + if (code == MESSAGE_WPS_ERROR) { + DEBUG_MSG_P(PSTR("[WIFI] WPS failed\n")); + } - if (code == MESSAGE_CONNECTING) { - DEBUG_MSG_P(PSTR("[WIFI] Connecting to %s\n"), parameter); - } + // ------------------------------------------------------------------------ - if (code == MESSAGE_CONNECT_WAITING) { - // too much noise - } + if (code == MESSAGE_SMARTCONFIG_START) { + DEBUG_MSG_P(PSTR("[WIFI] Smart Config started\n")); + } - if (code == MESSAGE_CONNECT_FAILED) { - DEBUG_MSG_P(PSTR("[WIFI] Could not connect to %s\n"), parameter); - } + if (code == MESSAGE_SMARTCONFIG_SUCCESS) { + DEBUG_MSG_P(PSTR("[WIFI] Smart Config succeded!\n")); + } - if (code == MESSAGE_CONNECTED) { - wifiStatus(); - } + if (code == MESSAGE_SMARTCONFIG_ERROR) { + DEBUG_MSG_P(PSTR("[WIFI] Smart Config failed\n")); + } - if (code == MESSAGE_ACCESSPOINT_CREATED) { - wifiStatus(); - } +} - if (code == MESSAGE_DISCONNECTED) { - DEBUG_MSG_P(PSTR("[WIFI] Disconnected\n")); - } +#endif // DEBUG_SUPPORT - if (code == MESSAGE_ACCESSPOINT_CREATING) { - DEBUG_MSG_P(PSTR("[WIFI] Creating access point\n")); - } +// ----------------------------------------------------------------------------- +// SETTINGS +// ----------------------------------------------------------------------------- - if (code == MESSAGE_ACCESSPOINT_FAILED) { - DEBUG_MSG_P(PSTR("[WIFI] Could not create access point\n")); - } +#if TERMINAL_SUPPORT - #endif // DEBUG_SUPPORT +void _wifiInitCommands() { - #if MQTT_SUPPORT - #if MDNS_SUPPORT - if (code == MESSAGE_CONNECTED) mdnsFindMQTT(); - #endif // MDNS_SUPPORT - #endif // MQTT_SUPPORT + settingsRegisterCommand(F("WIFI.RESET"), [](Embedis* e) { + _wifiConfigure(); + wifiDisconnect(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + settingsRegisterCommand(F("WIFI.AP"), [](Embedis* e) { + wifiStartAP(); + DEBUG_MSG_P(PSTR("+OK\n")); }); + #if defined(JUSTWIFI_ENABLE_WPS) + settingsRegisterCommand(F("WIFI.WPS"), [](Embedis* e) { + wifiStartWPS(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + #endif // defined(JUSTWIFI_ENABLE_WPS) + + #if defined(JUSTWIFI_ENABLE_SMARTCONFIG) + settingsRegisterCommand(F("WIFI.SMARTCONFIG"), [](Embedis* e) { + wifiStartSmartConfig(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + #endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG) + + settingsRegisterCommand(F("WIFI.SCAN"), [](Embedis* e) { + _wifiScan(); + DEBUG_MSG_P(PSTR("+OK\n")); + }); + +} + +#endif + +// ----------------------------------------------------------------------------- +// WEB +// ----------------------------------------------------------------------------- + +#if WEB_SUPPORT + +bool _wifiWebSocketOnReceive(const char * key, JsonVariant& value) { + if (strncmp(key, "wifi", 4) == 0) return true; + if (strncmp(key, "ssid", 4) == 0) return true; + if (strncmp(key, "pass", 4) == 0) return true; + if (strncmp(key, "ip", 2) == 0) return true; + if (strncmp(key, "gw", 2) == 0) return true; + if (strncmp(key, "mask", 4) == 0) return true; + if (strncmp(key, "dns", 3) == 0) return true; + return false; +} + +void _wifiWebSocketOnSend(JsonObject& root) { + root["maxNetworks"] = WIFI_MAX_NETWORKS; + root["wifiScan"] = getSetting("wifiScan", WIFI_SCAN_NETWORKS).toInt() == 1; + JsonArray& wifi = root.createNestedArray("wifi"); + for (byte i=0; i 0) && ((WiFi.getMode() & WIFI_STA) > 0)) { + + uint8_t * bssid = WiFi.BSSID(); + DEBUG_MSG_P(PSTR("[WIFI] ------------------------------------- MODE STA\n")); + DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), WiFi.SSID().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.localIP().toString().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.macAddress().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] DNS %s\n"), WiFi.dnsIP().toString().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] MASK %s\n"), WiFi.subnetMask().toString().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] HOST http://%s.local\n"), WiFi.hostname().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] BSSID %02X:%02X:%02X:%02X:%02X:%02X\n"), + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], bssid[6] + ); + DEBUG_MSG_P(PSTR("[WIFI] CH %d\n"), WiFi.channel()); + DEBUG_MSG_P(PSTR("[WIFI] RSSI %d\n"), WiFi.RSSI()); + footer = true; + + } + + if (((modes & WIFI_AP) > 0) && ((WiFi.getMode() & WIFI_AP) > 0)) { + DEBUG_MSG_P(PSTR("[WIFI] -------------------------------------- MODE AP\n")); + DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), getSetting("hostname").c_str()); + DEBUG_MSG_P(PSTR("[WIFI] PASS %s\n"), getSetting("adminPass", ADMIN_PASS).c_str()); + DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.softAPIP().toString().c_str()); + DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.softAPmacAddress().c_str()); + footer = true; + } + + if (WiFi.getMode() == 0) { + DEBUG_MSG_P(PSTR("[WIFI] ------------------------------------- MODE OFF\n")); + DEBUG_MSG_P(PSTR("[WIFI] No connection\n")); + footer = true; + } + + if (footer) { + DEBUG_MSG_P(PSTR("[WIFI] ----------------------------------------------\n")); + } + +} + +void wifiDebug() { + wifiDebug(WIFI_AP_STA); +} + +// ----------------------------------------------------------------------------- +// API +// ----------------------------------------------------------------------------- + +String getIP() { + if (WiFi.getMode() == WIFI_AP) { + return WiFi.softAPIP().toString(); + } + return WiFi.localIP().toString(); +} + +String getNetwork() { + if (WiFi.getMode() == WIFI_AP) { + return jw.getAPSSID(); + } + return WiFi.SSID(); +} + +bool wifiConnected() { + return jw.connected(); +} + +void wifiDisconnect() { + jw.disconnect(); +} + +void wifiStartAP(bool only) { + if (only) { + jw.enableSTA(false); + jw.disconnect(); + jw.resetReconnectTimeout(); + } + jw.enableAP(true); +} + +void wifiStartAP() { + wifiStartAP(true); +} + +#if defined(JUSTWIFI_ENABLE_WPS) +void wifiStartWPS() { + jw.startWPS(); +} +#endif // defined(JUSTWIFI_ENABLE_WPS) + +#if defined(JUSTWIFI_ENABLE_SMARTCONFIG) +void wifiStartSmartConfig() { + jw.startSmartConfig(); +} +#endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG) + +void wifiReconnectCheck() { + bool connected = false; + #if WEB_SUPPORT + if (wsConnected()) connected = true; + #endif + #if TELNET_SUPPORT + if (telnetConnected()) connected = true; + #endif + jw.setReconnectTimeout(connected ? 0 : WIFI_RECONNECT_INTERVAL); +} + +uint8_t wifiState() { + uint8_t state = 0; + if (jw.connected()) state += WIFI_STATE_STA; + if (jw.connectable()) state += WIFI_STATE_AP; + if (_wifi_wps_running) state += WIFI_STATE_WPS; + if (_wifi_smartconfig_running) state += WIFI_STATE_SMARTCONFIG; + return state; +} + +void wifiRegister(wifi_callback_f callback) { + jw.subscribe(callback); +} + +// ----------------------------------------------------------------------------- +// INITIALIZATION +// ----------------------------------------------------------------------------- + +void wifiSetup() { + + WiFi.setSleepMode(WIFI_SLEEP_MODE); + + _wifiInject(); + _wifiConfigure(); + + // Message callbacks + wifiRegister(_wifiCallback); + #if WIFI_AP_CAPTIVE + wifiRegister(_wifiCaptivePortal); + #endif + #if DEBUG_SUPPORT + wifiRegister(_wifiDebugCallback); + #endif + #if WEB_SUPPORT wsOnSendRegister(_wifiWebSocketOnSend); - wsOnAfterParseRegister(wifiConfigure); + wsOnReceiveRegister(_wifiWebSocketOnReceive); + wsOnAfterParseRegister(_wifiConfigure); + wsOnActionRegister(_wifiWebSocketOnAction); #endif + #if TERMINAL_SUPPORT + _wifiInitCommands(); + #endif + + // Register loop + espurnaRegisterLoop(wifiLoop); + } void wifiLoop() { + + // Main wifi loop jw.loop(); + + // Process captrive portal DNS queries if in AP mode only + #if WIFI_AP_CAPTIVE + if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) { + _wifi_dnsServer.processNextRequest(); + } + #endif + + // Do we have a pending scan? + if (_wifi_scan_client_id > 0) { + _wifiScan(_wifi_scan_client_id); + _wifi_scan_client_id = 0; + } + + // Check if we should disable AP + static unsigned long last = 0; + if (millis() - last > 60000) { + last = millis(); + _wifiCheckAP(); + } + } diff --git a/code/espurna/ws.ino b/code/espurna/ws.ino index 117947e0..de98f0e4 100644 --- a/code/espurna/ws.ino +++ b/code/espurna/ws.ino @@ -2,7 +2,7 @@ WEBSOCKET MODULE -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez */ @@ -21,11 +21,63 @@ Ticker _web_defer; std::vector _ws_on_send_callbacks; std::vector _ws_on_action_callbacks; std::vector _ws_on_after_parse_callbacks; +std::vector _ws_on_receive_callbacks; // ----------------------------------------------------------------------------- // Private methods // ----------------------------------------------------------------------------- +typedef struct { + IPAddress ip; + unsigned long timestamp = 0; +} ws_ticket_t; +ws_ticket_t _ticket[WS_BUFFER_SIZE]; + +void _onAuth(AsyncWebServerRequest *request) { + + webLog(request); + if (!webAuthenticate(request)) return request->requestAuthentication(); + + IPAddress ip = request->client()->remoteIP(); + unsigned long now = millis(); + unsigned short index; + for (index = 0; index < WS_BUFFER_SIZE; index++) { + if (_ticket[index].ip == ip) break; + if (_ticket[index].timestamp == 0) break; + if (now - _ticket[index].timestamp > WS_TIMEOUT) break; + } + if (index == WS_BUFFER_SIZE) { + request->send(429); + } else { + _ticket[index].ip = ip; + _ticket[index].timestamp = now; + request->send(200, "text/plain", "OK"); + } + +} + +bool _wsAuth(AsyncWebSocketClient * client) { + + IPAddress ip = client->remoteIP(); + unsigned long now = millis(); + unsigned short index = 0; + + for (index = 0; index < WS_BUFFER_SIZE; index++) { + if ((_ticket[index].ip == ip) && (now - _ticket[index].timestamp < WS_TIMEOUT)) break; + } + + if (index == WS_BUFFER_SIZE) { + DEBUG_MSG_P(PSTR("[WEBSOCKET] Validation check failed\n")); + wsSend_P(client->id(), PSTR("{\"message\": 10}")); + return false; + } + + return true; + +} + +// ----------------------------------------------------------------------------- + #if MQTT_SUPPORT void _wsMQTTCallback(unsigned int type, const char * topic, const char * payload) { if (type == MQTT_CONNECT_EVENT) wsSend_P(PSTR("{\"mqttStatus\": true}")); @@ -93,26 +145,42 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) { DEBUG_MSG_P(PSTR("[WEBSOCKET] Requested action: %s\n"), action); - if (strcmp(action, "reboot") == 0) deferredReset(100, CUSTOM_RESET_WEB); - if (strcmp(action, "reconnect") == 0) _web_defer.once_ms(100, wifiDisconnect); + if (strcmp(action, "reboot") == 0) { + deferredReset(100, CUSTOM_RESET_WEB); + return; + } + + if (strcmp(action, "reconnect") == 0) { + _web_defer.once_ms(100, wifiDisconnect); + return; + } + + if (strcmp(action, "factory_reset") == 0) { + DEBUG_MSG_P(PSTR("\n\nFACTORY RESET\n\n")); + resetSettings(); + deferredReset(100, CUSTOM_RESET_FACTORY); + return; + } JsonObject& data = root["data"]; if (data.success()) { // Callbacks for (unsigned char i = 0; i < _ws_on_action_callbacks.size(); i++) { - (_ws_on_action_callbacks[i])(action, data); + (_ws_on_action_callbacks[i])(client_id, action, data); } // Restore configuration via websockets if (strcmp(action, "restore") == 0) { - if (settingsRestore(data)) { + if (settingsRestoreJson(data)) { wsSend_P(client_id, PSTR("{\"message\": 5}")); } else { wsSend_P(client_id, PSTR("{\"message\": 4}")); } } + return; + } }; @@ -154,6 +222,19 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) { continue; } + // Check if key has to be processed + bool found = false; + for (unsigned char i = 0; i < _ws_on_receive_callbacks.size(); i++) { + found |= (_ws_on_receive_callbacks[i])(key.c_str(), value); + // TODO: remove this to call all OnReceiveCallbacks with the + // current key/value + if (found) break; + } + if (!found) { + delSetting(key); + continue; + } + // Store values if (value.is()) { if (_wsStore(key, value.as())) changed = true; @@ -175,17 +256,12 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) { if (save) { // Callbacks - for (unsigned char i = 0; i < _ws_on_after_parse_callbacks.size(); i++) { - (_ws_on_after_parse_callbacks[i])(); - } + wsReload(); // This should got to callback as well // but first change management has to be in place #if MQTT_SUPPORT - if (changedMQTT) { - mqttConfigure(); - mqttDisconnect(); - } + if (changedMQTT) mqttReset(); #endif // Persist settings @@ -203,9 +279,30 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) { } +void _wsUpdate(JsonObject& root) { + root["heap"] = getFreeHeap(); + root["uptime"] = getUptime(); + root["rssi"] = WiFi.RSSI(); + root["loadaverage"] = systemLoadAverage(); + #if ADC_MODE_VALUE == ADC_VCC + root["vcc"] = ESP.getVcc(); + #endif + #if NTP_SUPPORT + if (ntpSynced()) root["now"] = now(); + #endif +} + +bool _wsOnReceive(const char * key, JsonVariant& value) { + if (strncmp(key, "ws", 2) == 0) return true; + if (strncmp(key, "admin", 5) == 0) return true; + if (strncmp(key, "hostname", 8) == 0) return true; + if (strncmp(key, "webPort", 7) == 0) return true; + return false; +} + void _wsOnStart(JsonObject& root) { - #if WEB_FORCE_PASS_CHANGE + #if USE_PASSWORD && WEB_FORCE_PASS_CHANGE String adminPass = getSetting("adminPass", ADMIN_PASS); bool changePassword = adminPass.equals(ADMIN_PASS); #else @@ -220,28 +317,41 @@ void _wsOnStart(JsonObject& root) { char chipid[7]; snprintf_P(chipid, sizeof(chipid), PSTR("%06X"), ESP.getChipId()); + uint8_t * bssid = WiFi.BSSID(); + char bssid_str[20]; + snprintf_P(bssid_str, sizeof(bssid_str), + PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5] + ); root["webMode"] = WEB_MODE_NORMAL; root["app_name"] = APP_NAME; root["app_version"] = APP_VERSION; root["app_build"] = buildTime(); + root["app_revision"] = APP_REVISION; root["manufacturer"] = MANUFACTURER; root["chipid"] = String(chipid); root["mac"] = WiFi.macAddress(); + root["bssid"] = String(bssid_str); + root["channel"] = WiFi.channel(); root["device"] = DEVICE; root["hostname"] = getSetting("hostname"); root["network"] = getNetwork(); root["deviceip"] = getIP(); - root["uptime"] = getUptime(); - root["heap"] = getFreeHeap(); root["sketch_size"] = ESP.getSketchSize(); root["free_size"] = ESP.getFreeSketchSpace(); + root["sdk"] = ESP.getSdkVersion(); + root["core"] = getCoreVersion(); + + _wsUpdate(root); root["btnDelay"] = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY).toInt(); root["webPort"] = getSetting("webPort", WEB_PORT).toInt(); - root["tmpUnits"] = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt(); - root["tmpCorrection"] = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat(); + root["wsAuth"] = getSetting("wsAuth", WS_AUTHENTICATION).toInt() == 1; + #if TERMINAL_SUPPORT + root["cmdVisible"] = 1; + #endif } @@ -256,6 +366,11 @@ void _wsStart(uint32_t client_id) { void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ if (type == WS_EVT_CONNECT) { + + #ifndef NOWSAUTH + if (!_wsAuth(client)) return; + #endif + IPAddress ip = client->remoteIP(); DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u connected, ip: %d.%d.%d.%d, url: %s\n"), client->id(), ip[0], ip[1], ip[2], ip[3], server->url()); _wsStart(client->id()); @@ -285,8 +400,17 @@ void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTy } +void _wsLoop() { + static unsigned long last = 0; + if (!wsConnected()) return; + if (millis() - last > WS_UPDATE_INTERVAL) { + last = millis(); + wsSend(_wsUpdate); + } +} + // ----------------------------------------------------------------------------- -// Piblic API +// Public API // ----------------------------------------------------------------------------- bool wsConnected() { @@ -297,6 +421,10 @@ void wsOnSendRegister(ws_on_send_callback_f callback) { _ws_on_send_callbacks.push_back(callback); } +void wsOnReceiveRegister(ws_on_receive_callback_f callback) { + _ws_on_receive_callbacks.push_back(callback); +} + void wsOnActionRegister(ws_on_action_callback_f callback) { _ws_on_action_callbacks.push_back(callback); } @@ -312,6 +440,7 @@ void wsSend(ws_on_send_callback_f callback) { callback(root); String output; root.printTo(output); + jsonBuffer.clear(); _ws.textAll((char *) output.c_str()); } } @@ -336,6 +465,7 @@ void wsSend(uint32_t client_id, ws_on_send_callback_f callback) { callback(root); String output; root.printTo(output); + jsonBuffer.clear(); _ws.text(client_id, (char *) output.c_str()); } @@ -349,19 +479,25 @@ void wsSend_P(uint32_t client_id, PGM_P payload) { _ws.text(client_id, buffer); } -void wsConfigure() { - _ws.setAuthentication(WEB_USERNAME, (const char *) getSetting("adminPass", ADMIN_PASS).c_str()); +// This method being public makes +// _ws_on_after_parse_callbacks strange here, +// it should belong somewhere else. +void wsReload() { + for (unsigned char i = 0; i < _ws_on_after_parse_callbacks.size(); i++) { + (_ws_on_after_parse_callbacks[i])(); + } } void wsSetup() { _ws.onEvent(_wsEvent); - wsConfigure(); webServer()->addHandler(&_ws); + webServer()->on("/auth", HTTP_GET, _onAuth); #if MQTT_SUPPORT mqttRegister(_wsMQTTCallback); #endif wsOnSendRegister(_wsOnStart); - wsOnAfterParseRegister(wsConfigure); + wsOnReceiveRegister(_wsOnReceive); + espurnaRegisterLoop(_wsLoop); } #endif // WEB_SUPPORT diff --git a/code/extra_scripts.py b/code/extra_scripts.py new file mode 100644 index 00000000..1cb1ed4c --- /dev/null +++ b/code/extra_scripts.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +from subprocess import call +import os +import time + +Import("env") + +# ------------------------------------------------------------------------------ +# Utils +# ------------------------------------------------------------------------------ + +class Color(object): + BLACK = '\x1b[1;30m' + RED = '\x1b[1;31m' + GREEN = '\x1b[1;32m' + YELLOW = '\x1b[1;33m' + BLUE = '\x1b[1;34m' + MAGENTA = '\x1b[1;35m' + CYAN = '\x1b[1;36m' + WHITE = '\x1b[1;37m' + LIGHT_GREY = '\x1b[0;30m' + LIGHT_RED = '\x1b[0;31m' + LIGHT_GREEN = '\x1b[0;32m' + LIGHT_YELLOW = '\x1b[0;33m' + LIGHT_BLUE = '\x1b[0;34m' + LIGHT_MAGENTA = '\x1b[0;35m' + LIGHT_CYAN = '\x1b[0;36m' + LIGHT_WHITE = '\x1b[0;37m' + +def clr(color, text): + return color + str(text) + '\x1b[0m' + +# ------------------------------------------------------------------------------ +# Callbacks +# ------------------------------------------------------------------------------ + +def remove_float_support(): + + flags = " ".join(env['LINKFLAGS']) + flags = flags.replace("-u _printf_float", "") + flags = flags.replace("-u _scanf_float", "") + newflags = flags.split() + + env.Replace( + LINKFLAGS = newflags + ) + +def cpp_check(source, target, env): + print("Started cppcheck...\n") + call(["cppcheck", os.getcwd()+"/espurna", "--force", "--enable=all"]) + print("Finished cppcheck...\n") + +def check_size(source, target, env): + time.sleep(2) + size = target[0].get_size() + print clr(Color.LIGHT_BLUE, "Binary size: %s bytes" % size) + #if size > 512000: + # print clr(Color.LIGHT_RED, "File too large for OTA!") + # Exit(1) + +# ------------------------------------------------------------------------------ +# Hooks +# ------------------------------------------------------------------------------ + +remove_float_support() + +#env.AddPreAction("buildprog", cpp_check) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", check_size) diff --git a/code/gulpfile.js b/code/gulpfile.js index 9ba13b30..ea14061c 100644 --- a/code/gulpfile.js +++ b/code/gulpfile.js @@ -2,7 +2,7 @@ ESP8266 file system builder -Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2018 by Xose Pérez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +19,9 @@ along with this program. If not, see . */ +/*eslint quotes: ["error", "single"]*/ +/*eslint-env es6*/ + // ----------------------------------------------------------------------------- // File system builder // ----------------------------------------------------------------------------- @@ -26,92 +29,108 @@ along with this program. If not, see . const fs = require('fs'); const gulp = require('gulp'); const htmlmin = require('gulp-htmlmin'); -const cleancss = require('gulp-clean-css'); const uglify = require('gulp-uglify'); const gzip = require('gulp-gzip'); const inline = require('gulp-inline'); const inlineImages = require('gulp-css-base64'); const favicon = require('gulp-base64-favicon'); const htmllint = require('gulp-htmllint'); -const gutil = require('gulp-util'); +const log = require('fancy-log'); +const csslint = require('gulp-csslint'); +const crass = require('gulp-crass'); +const replace = require('gulp-replace'); const dataFolder = 'espurna/data/'; const staticFolder = 'espurna/static/'; -String.prototype.replaceAll = function(search, replacement) { - var target = this; - return target.split(search).join(replacement); -}; - var toHeader = function(filename) { var source = dataFolder + filename; var destination = staticFolder + filename + '.h'; - var safename = filename.replaceAll('.', '_'); + var safename = filename.split('.').join('_'); var wstream = fs.createWriteStream(destination); wstream.on('error', function (err) { - console.log(err); + log.error(err); }); var data = fs.readFileSync(source); wstream.write('#define ' + safename + '_len ' + data.length + '\n'); - wstream.write('const uint8_t ' + safename + '[] PROGMEM = {') + wstream.write('const uint8_t ' + safename + '[] PROGMEM = {'); - for (i=0; i 0) { issues.forEach(function (issue) { - gutil.log(gutil.colors.cyan('[gulp-htmllint] ') + gutil.colors.white(filepath + ' [' + issue.line + ',' + issue.column + ']: ') + gutil.colors.red('(' + issue.code + ') ' + issue.msg)); + log.info( + '[gulp-htmllint] ' + + filepath + ' [' + + issue.line + ',' + + issue.column + ']: ' + + '(' + issue.code + ') ' + + issue.msg + ); }); process.exitCode = 1; } -} +}; gulp.task('build_certs', function() { toHeader('server.cer'); toHeader('server.key'); }); +gulp.task('csslint', function() { + gulp.src('html/*.css'). + pipe(csslint({ids: false})). + pipe(csslint.formatter()); +}); + gulp.task('buildfs_embeded', ['buildfs_inline'], function() { toHeader('index.html.gz'); }); gulp.task('buildfs_inline', function() { - return gulp.src('html/*.html') - .pipe(htmllint({ + return gulp.src('html/*.html'). + pipe(htmllint({ 'failOnError': true, 'rules': { 'id-class-style': false, 'label-req-for': false, } - }, htmllintReporter)) - .pipe(favicon()) - .pipe(inline({ + }, htmllintReporter)). + pipe(favicon()). + pipe(inline({ base: 'html/', js: [uglify], - css: [cleancss, inlineImages], + css: [crass, inlineImages], disabledTypes: ['svg', 'img'] - })) - .pipe(htmlmin({ + })). + pipe(htmlmin({ collapseWhitespace: true, removeComments: true, minifyCSS: true, minifyJS: true - })) - .pipe(gzip()) - .pipe(gulp.dest(dataFolder)); -}) + })). + pipe(replace('pure-', 'p-')). + pipe(gzip()). + pipe(gulp.dest(dataFolder)); +}); + gulp.task('default', ['buildfs_embeded']); diff --git a/code/html/custom.css b/code/html/custom.css index 0542eca8..05711fc2 100644 --- a/code/html/custom.css +++ b/code/html/custom.css @@ -1,152 +1,115 @@ +/* ----------------------------------------------------------------------------- + General + -------------------------------------------------------------------------- */ + #menu .pure-menu-heading { font-size: 100%; padding: .5em .5em; + white-space: normal; + text-transform: initial; } -.header h2 { - font-size: 1em; -} -.panel { - display: none; -} -.footer { - position: absolute; - bottom: 0; - left: 0; - right: 0; - padding: 10px; - font-size: 80%; - color: #999; -} -#menu .footer a { - text-decoration: none; - padding: 0px; -} -.content { - margin: 0px; -} -.page { - margin-top: 10px; -} -.pure-button { - color: white; - padding: 8px 8px; - border-radius: 4px; - text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -} -.main-buttons { - margin: 50px auto; - text-align: center; -} -.main-buttons button { - width: 100px; - margin: 5px auto; -} -.button-update-password, -.button-update { - background: #1f8dd6; -} -.button-reboot, -.button-reconnect, -.button-ha-del, -.button-rfb-forget { - background: rgb(202, 60, 60); -} -.button-upgrade { - background: rgb(202, 60, 60); - margin-left: 5px; -} -.button-upgrade-browse, -.button-ha-add, -.button-apikey { - background: rgb(0, 202, 0); - margin-left: 5px; -} -.button-add-network, -.button-rfb-learn { - background: rgb(28, 184, 65); -} -.button-del-network { - background: rgb(202, 60, 60); - letter-spacing: 0px; -} -.button-more-network, -.button-rfb-send { - background: rgb(223, 117, 20); -} -.button-settings-backup, -.button-settings-restore { - background: rgb(0, 202, 0); - margin-bottom: 10px; -} + .pure-g { - margin-bottom: 0px; + margin-bottom: 0; } + .pure-form legend { font-weight: bold; letter-spacing: 0; margin: 10px 0 1em 0; } -.l-box { - padding-right: 1px; + +.pure-form .pure-g > label { + margin: .4em 0 .2em; } + .pure-form input { margin-bottom: 10px; } + .pure-form input[type=text][disabled] { color: #777777; } -div.hint { - font-size: 80%; - color: #ccc; - margin: -10px 0 10px 0; -} -.break { - margin-top: 5px; + +@media screen and (max-width: 32em) { + .header > h1 { + line-height: 100%; + font-size: 2em; + } } -#networks .pure-g { - padding: 10px 0 10px 0; - margin-bottom: 5px; - border-bottom: 2px dashed #e5e5e5; + +h2 { + font-size: 1em; } -#networks .more { + +.panel { display: none; } + +.block { + display: block; +} + +.content { + margin: 0; +} + +.page { + margin-top: 10px; +} + +.hint { + color: #ccc; + font-size: 80%; + margin: -10px 0 10px 0; +} + +.hint a { + color:inherit; +} + legend.module, .module { display: none; } + .template { display: none; } + input[name=upgrade] { display: none; } -#upgrade-progress { - display: none; + +select { + margin-bottom: 10px; width: 100%; - height: 20px; - margin-top: 10px; } + input.center { - margin-bottom: 0px; + margin-bottom: 0; } + div.center { margin: .5em 0 1em; } + .webmode { display: none; } + #credentials { font-size: 200%; - text-align: center; height: 100px; - width: 400px; - position: fixed; - top: 50%; left: 50%; - margin-top: -50px; margin-left: -200px; + margin-top: -50px; + position: fixed; + text-align: center; + top: 50%; + width: 400px; } + div.state { border-top: 1px solid #eee; margin-top: 20px; @@ -161,40 +124,198 @@ div.state { font-size: 80%; font-weight: bold; } + .right { text-align: right; } +.pure-g span.terminal, +.pure-g textarea.terminal { + font-family: 'Courier New', monospace; + font-size: 80%; + line-height: 100%; + background-color: #000; + color: #0F0; +} + +/* ----------------------------------------------------------------------------- + Buttons + -------------------------------------------------------------------------- */ + +.pure-button { + border-radius: 4px; + color: white; + letter-spacing: 0; + margin-bottom: 10px; + padding: 8px 8px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} + +.main-buttons { + margin: 20px auto; + text-align: center; +} +.main-buttons button { + width: 100px; +} + +.button-reboot, +.button-reconnect, +.button-ha-del, +.button-rfb-forget, +.button-del-network, +.button-del-schedule, +.button-dbg-clear, +.button-upgrade, +.button-settings-factory { + background: rgb(192, 0, 0); /* redish */ +} + +.button-update, +.button-update-password, +.button-add-network, +.button-rfb-learn, +.button-upgrade-browse, +.button-ha-add, +.button-ha-config, +.button-settings-backup, +.button-settings-restore, +.button-dbgcmd, +.button-apikey { + background: rgb(0, 192, 0); /* green */ +} + +.button-add-switch-schedule, +.button-add-light-schedule { + background: rgb(0, 192, 0); /* green */ + display: none; +} + +.button-more-network, +.button-more-schedule, +.button-wifi-scan, +.button-rfb-send { + background: rgb(255, 128, 0); /* orange */ +} + +.button-upgrade-browse, +.button-dbgcmd, +.button-ha-add, +.button-apikey, +.button-upgrade { + margin-left: 5px; +} + +/* ----------------------------------------------------------------------------- + Sliders + -------------------------------------------------------------------------- */ + input.slider { margin-top: 10px; } + span.slider { font-size: 70%; + letter-spacing: 0; margin-left: 10px; margin-top: 7px; - letter-spacing: 0; } + +/* ----------------------------------------------------------------------------- + Loading + -------------------------------------------------------------------------- */ + +.loading { + background-image: url('images/loading.gif'); + display: none; + height: 20px; + margin: 8px 0 0 10px; + width: 20px; +} + +/* ----------------------------------------------------------------------------- + Menu + -------------------------------------------------------------------------- */ + +#menu .small { + font-size: 60%; + padding-left: 9px; +} + +#menu div.footer { + color: #999; + font-size: 80%; + padding: 10px; +} +#menu div.footer a { + padding: 0; + text-decoration: none; +} + +/* ----------------------------------------------------------------------------- + RF Bridge panel + -------------------------------------------------------------------------- */ + #panel-rfb fieldset { margin: 10px 2px; padding: 20px; } + #panel-rfb input { margin-right: 5px; } + #panel-rfb label { padding-top: 5px; } + #panel-rfb input { text-align: center; } + +/* ----------------------------------------------------------------------------- + Admin panel + -------------------------------------------------------------------------- */ + +#upgrade-progress { + display: none; + height: 20px; + margin-top: 10px; + width: 100%; +} + #uploader, #downloader { display: none; } -.panel.block { - display: block; + +/* ----------------------------------------------------------------------------- + Wifi panel + -------------------------------------------------------------------------- */ + +#networks .pure-g, +#schedules .pure-g { + border-bottom: 1px solid #eee; + margin-bottom: 10px; + padding: 10px 0 10px 0; } -select { - width: 100%; + +#networks .more { + display: none; +} + +#haConfig, +#scanResult { + margin-top: 10px; + display: none; + padding: 10px; +} + +/* ----------------------------------------------------------------------------- + Logs + -------------------------------------------------------------------------- */ + +#weblog { + height: 400px; margin-bottom: 10px; } diff --git a/code/html/custom.js b/code/html/custom.js index 9b4c9706..ae09de5a 100644 --- a/code/html/custom.js +++ b/code/html/custom.js @@ -1,8 +1,11 @@ var websock; var password = false; var maxNetworks; +var maxSchedules; var messages = []; -var webhost; +var free_size = 0; + +var urls = {}; var numChanged = 0; var numReboot = 0; @@ -10,21 +13,24 @@ var numReconnect = 0; var numReload = 0; var useWhite = false; -var manifest; +var useCCT = false; + +var now = 0; +var ago = 0; // ----------------------------------------------------------------------------- // Messages // ----------------------------------------------------------------------------- function initMessages() { - messages[ 1] = "Remote update started"; - messages[ 2] = "OTA update started"; - messages[ 3] = "Error parsing data!"; - messages[ 4] = "The file does not look like a valid configuration backup or is corrupted"; - messages[ 5] = "Changes saved. You should reboot your board now"; - messages[ 7] = "Passwords do not match!"; - messages[ 8] = "Changes saved"; - messages[ 9] = "No changes detected"; + messages[1] = "Remote update started"; + messages[2] = "OTA update started"; + messages[3] = "Error parsing data!"; + messages[4] = "The file does not look like a valid configuration backup or is corrupted"; + messages[5] = "Changes saved. You should reboot your board now"; + messages[7] = "Passwords do not match!"; + messages[8] = "Changes saved"; + messages[9] = "No changes detected"; messages[10] = "Session expired, please reload page..."; } @@ -33,9 +39,12 @@ function sensorName(id) { "DHT", "Dallas", "Emon Analog", "Emon ADC121", "Emon ADS1X15", "HLW8012", "V9261F", "ECH1560", "Analog", "Digital", "Events", "PMSX003", "BMX280", "MHZ19", "SI7021", - "SHT3X I2C", "BH1750" + "SHT3X I2C", "BH1750", "PZEM004T", "AM2320 I2C", "GUVAS12SD", + "TMP3X", "HC-SR04", "SenseAir", "GeigerTicks", "GeigerCPM" ]; - if (1 <= id && id <= names.length) return names[id-1]; + if (1 <= id && id <= names.length) { + return names[id - 1]; + } return null; } @@ -45,18 +54,23 @@ function magnitudeType(type) { "Current", "Voltage", "Active Power", "Apparent Power", "Reactive Power", "Power Factor", "Energy", "Energy (delta)", "Analog", "Digital", "Events", - "PM1.0", "PM2.5", "PM10", "CO2", "Lux" + "PM1.0", "PM2.5", "PM10", "CO2", "Lux", "UV", "Distance" , "HCHO", + "Local Dose Rate", "Local Dose Rate" ]; - if (1 <= type && type <= types.length) return types[type-1]; + if (1 <= type && type <= types.length) { + return types[type - 1]; + } return null; } function magnitudeError(error) { var errors = [ "OK", "Out of Range", "Warming Up", "Timeout", "Wrong ID", - "CRC Error", "I2C Error", "GPIO Error" + "Data Error", "I2C Error", "GPIO Error", "Calibration error" ]; - if (0 <= error && error < errors.length) return errors[error]; + if (0 <= error && error < errors.length) { + return errors[error]; + } return "Error " + error; } @@ -64,48 +78,147 @@ function magnitudeError(error) { // Utils // ----------------------------------------------------------------------------- -// http://www.the-art-of-web.com/javascript/validate-password/ -function checkPassword(str) { - // at least one lowercase and one uppercase letter or number - // at least five characters (letters, numbers or special characters) - var re = /^(?=.*[A-Z\d])(?=.*[a-z])[\w~!@#$%^&*\(\)<>,.\?;:{}\[\]\\|]{5,}$/; - return re.test(str); +$.fn.enterKey = function (fnc) { + return this.each(function () { + $(this).keypress(function (ev) { + var keycode = parseInt(ev.keyCode ? ev.keyCode : ev.which, 10); + if (13 === keycode) { + return fnc.call(this, ev); + } + }); + }); +}; + +function keepTime() { + + $("span[name='ago']").html(ago); + ago++; + + if (0 === now) { return; } + var date = new Date(now * 1000); + var text = date.toISOString().substring(0, 19).replace("T", " "); + $("input[name='now']").val(text); + $("span[name='now']").html(text); + now++; + } function zeroPad(number, positions) { - var zeros = ''; - for (var i = 0; i < positions; i++) zeros += "0"; + var zeros = ""; + for (var i = 0; i < positions; i++) { + zeros += "0"; + } return (zeros + number).slice(-positions); } +function loadTimeZones() { + + var time_zones = [ + -720, -660, -600, -570, -540, + -480, -420, -360, -300, -240, + -210, -180, -120, -60, 0, + 60, 120, 180, 210, 240, + 270, 300, 330, 345, 360, + 390, 420, 480, 510, 525, + 540, 570, 600, 630, 660, + 720, 765, 780, 840 + ]; + + for (var i in time_zones) { + var value = time_zones[i]; + var offset = value >= 0 ? value : -value; + var text = "GMT" + (value >= 0 ? "+" : "-") + + zeroPad(parseInt(offset / 60, 10), 2) + ":" + + zeroPad(offset % 60, 2); + $("select[name='ntpOffset']").append( + $(""). + attr("value",value). + text(text)); + } + +} + function validateForm(form) { + // http://www.the-art-of-web.com/javascript/validate-password/ + // at least one lowercase and one uppercase letter or number + // at least five characters (letters, numbers or special characters) + var re_password = /^(?=.*[A-Z\d])(?=.*[a-z])[\w~!@#$%^&*\(\)<>,.\?;:{}\[\]\\|]{5,}$/; + // password var adminPass1 = $("input[name='adminPass']", form).first().val(); - if (adminPass1.length > 0 && !checkPassword(adminPass1)) { + if (adminPass1.length > 0 && !re_password.test(adminPass1)) { alert("The password you have entered is not valid, it must have at least 5 characters, 1 lowercase and 1 uppercase or number!"); return false; } var adminPass2 = $("input[name='adminPass']", form).last().val(); - if (adminPass1 != adminPass2) { + if (adminPass1 !== adminPass2) { alert("Passwords are different!"); return false; } + // RFCs mandate that a hostname's labels may contain only + // the ASCII letters 'a' through 'z' (case-insensitive), + // the digits '0' through '9', and the hyphen. + // Hostname labels cannot begin or end with a hyphen. + // No other symbols, punctuation characters, or blank spaces are permitted. + + // Negative lookbehind does not work in Javascript + // var re_hostname = new RegExp('^(?!-)[A-Za-z0-9-]{1,32}(?= 0) { + data[name] = [value]; + } else { + data[name] = value; + } + +} function getData(form) { @@ -114,54 +227,38 @@ function getData(form) { // Populate data $("input,select", form).each(function() { var name = $(this).attr("name"); - if (name) { - - // Do not report these fields - if (name == "filename") return; - if (name == "rfbcode") return; - - // Grab the value - if ($(this).attr('type') == 'checkbox') { - value = $(this).is(':checked') ? 1 : 0; - } else if ($(this).attr('type') == 'radio') { - if (!$(this).is(':checked')) return; - value = $(this).val(); - } else { - value = $(this).val(); - } - - // Build the object - if (name in data) { - if (!Array.isArray(data[name])) data[name] = [data[name]]; - data[name].push(value); - } else if (is_group.indexOf(name) >= 0) { - data[name] = [value]; - } else { - data[name] = value; - } - + var value = getValue(this); + if (null !== value) { + addValue(data, name, value); } }); + // Post process + addValue(data, "schSwitch", 0xFF); + delete data["filename"]; + delete data["rfbcode"]; + return data; } function randomString(length, chars) { - var mask = ''; - if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz'; - if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - if (chars.indexOf('#') > -1) mask += '0123456789'; - if (chars.indexOf('@') > -1) mask += 'ABCDEF'; - if (chars.indexOf('!') > -1) mask += '~`!@#$%^&*()_+-={}[]:";\'<>?,./|\\'; - var result = ''; - for (var i = length; i > 0; --i) result += mask[Math.round(Math.random() * (mask.length - 1))]; + var mask = ""; + if (chars.indexOf("a") > -1) { mask += "abcdefghijklmnopqrstuvwxyz"; } + if (chars.indexOf("A") > -1) { mask += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } + if (chars.indexOf("#") > -1) { mask += "0123456789"; } + if (chars.indexOf("@") > -1) { mask += "ABCDEF"; } + if (chars.indexOf("!") > -1) { mask += "~`!@#$%^&*()_+-={}[]:\";'<>?,./|\\"; } + var result = ""; + for (var i = length; i > 0; --i) { + result += mask[Math.round(Math.random() * (mask.length - 1))]; + } return result; } function generateAPIKey() { - var apikey = randomString(16, '@#'); - $("input[name=\"apiKey\"]").val(apikey); + var apikey = randomString(16, "@#"); + $("input[name='apiKey']").val(apikey); return false; } @@ -177,104 +274,113 @@ function getJson(str) { // Actions // ----------------------------------------------------------------------------- -function doReload(milliseconds) { - milliseconds = (typeof milliseconds == 'undefined') ? 0 : parseInt(milliseconds); - setTimeout(function() { - window.location.reload(); - }, milliseconds); +function sendAction(action, data) { + websock.send(JSON.stringify({action: action, data: data})); } -function doUpdate() { - - var form = $("#formSave"); - if (validateForm(form)) { - - // Get data - var data = getData(form); - websock.send(JSON.stringify({'config': data})); - - // Empty special fields - $(".pwrExpected").val(0); - $("input[name='pwrResetCalibration']") - .prop("checked", false) - .iphoneStyle("refresh"); +function sendConfig(data) { + websock.send(JSON.stringify({config: data})); +} - // Change handling - numChanged = 0; - setTimeout(function() { +function resetOriginals() { + $("input,select").each(function() { + $(this).attr("original", $(this).val()); + }); + numReboot = numReconnect = numReload = 0; +} - if (numReboot > 0) { - var response = window.confirm("You have to reboot the board for the changes to take effect, do you want to do it now?"); - if (response == true) doReboot(false); - } else if (numReconnect > 0) { - var response = window.confirm("You have to reconnect to the WiFi for the changes to take effect, do you want to do it now?"); - if (response == true) doReconnect(false); - } else if (numReload > 0) { - var response = window.confirm("You have to reload the page to see the latest changes, do you want to do it now?"); - if (response == true) doReload(); - } +function doReload(milliseconds) { + setTimeout(function() { + window.location.reload(); + }, parseInt(milliseconds, 10)); +} - resetOriginals(); +/** + * Check a file object to see if it is a valid firmware image + * The file first byte should be 0xE9 + * @param {file} file File object + * @param {Function} callback Function to call back with the result + */ +function checkFirmware(file, callback) { - }, 1000); + var reader = new FileReader(); - } + reader.onloadend = function(evt) { + if (FileReader.DONE === evt.target.readyState) { + callback(0xE9 === evt.target.result.charCodeAt(0)); + } + }; - return false; + var blob = file.slice(0, 1); + reader.readAsBinaryString(blob); } function doUpgrade() { - var contents = $("input[name='upgrade']")[0].files[0]; - if (typeof contents == 'undefined') { + var file = $("input[name='upgrade']")[0].files[0]; + + if (typeof file === "undefined") { alert("First you have to select a file from your computer."); return false; } - var filename = $("input[name='upgrade']").val().split('\\').pop(); - - var data = new FormData(); - data.append('upgrade', contents, filename); - - $.ajax({ - // Your server script to process the upload - url: webhost + 'upgrade', - type: 'POST', + if (file.size > free_size) { + alert("Image it too large to fit in the available space for OTA. Consider doing a two-step update."); + return false; + } - // Form data - data: data, + checkFirmware(file, function(ok) { - // Tell jQuery not to process data or worry about content-type - // You *must* include these options! - cache: false, - contentType: false, - processData: false, + if (!ok) { + alert("The file does not seem to be a valid firmware image."); + return; + } - success: function(data, text) { - $("#upgrade-progress").hide(); - if (data == 'OK') { - alert("Firmware image uploaded, board rebooting. This page will be refreshed in 5 seconds."); - doReload(5000); - } else { - alert("There was an error trying to upload the new image, please try again (" + data + ")."); + var data = new FormData(); + data.append("upgrade", file, file.name); + + $.ajax({ + + // Your server script to process the upload + url: urls.upgrade.href, + type: "POST", + + // Form data + data: data, + + // Tell jQuery not to process data or worry about content-type + // You *must* include these options! + cache: false, + contentType: false, + processData: false, + + success: function(data, text) { + $("#upgrade-progress").hide(); + if ("OK" === data) { + alert("Firmware image uploaded, board rebooting. This page will be refreshed in 5 seconds."); + doReload(5000); + } else { + alert("There was an error trying to upload the new image, please try again (" + data + ")."); + } + }, + + // Custom XMLHttpRequest + xhr: function() { + $("#upgrade-progress").show(); + var myXhr = $.ajaxSettings.xhr(); + if (myXhr.upload) { + // For handling the progress of the upload + myXhr.upload.addEventListener("progress", function(e) { + if (e.lengthComputable) { + $("progress").attr({ value: e.loaded, max: e.total }); + } + } , false); + } + return myXhr; } - }, - - // Custom XMLHttpRequest - xhr: function() { - $("#upgrade-progress").show(); - var myXhr = $.ajaxSettings.xhr(); - if (myXhr.upload) { - // For handling the progress of the upload - myXhr.upload.addEventListener('progress', function(e) { - if (e.lengthComputable) { - $('progress').attr({ value: e.loaded, max: e.total }); - } - } , false); - } - return myXhr; - }, + + }); }); @@ -285,74 +391,127 @@ function doUpgrade() { function doUpdatePassword() { var form = $("#formPassword"); if (validateForm(form)) { - var data = getData(form); - websock.send(JSON.stringify({'config': data})); + sendConfig(getData(form)); } return false; } -function doReboot(ask) { - - ask = (typeof ask == 'undefined') ? true : ask; +function checkChanges() { if (numChanged > 0) { var response = window.confirm("Some changes have not been saved yet, do you want to save them first?"); - if (response == true) return doUpdate(); + if (response) { + doUpdate(); + } } - if (ask) { - var response = window.confirm("Are you sure you want to reboot the device?"); - if (response == false) return false; +} + +function doAction(question, action) { + + checkChanges(); + + if (question) { + var response = window.confirm(question); + if (false === response) { + return false; + } } - websock.send(JSON.stringify({'action': 'reboot'})); + sendAction(action, {}); doReload(5000); return false; } +function doReboot(ask) { + + var question = (typeof ask === "undefined" || false === ask) ? + null : + "Are you sure you want to reboot the device?"; + return doAction(question, "reboot"); + +} + function doReconnect(ask) { - ask = (typeof ask == 'undefined') ? true : ask; + var question = (typeof ask === "undefined" || false === ask) ? + null : + "Are you sure you want to disconnect from the current WIFI network?"; + return doAction(question, "reconnect"); - if (numChanged > 0) { - var response = window.confirm("Some changes have not been saved yet, do you want to save them first?"); - if (response == true) return doUpdate(); - } +} + +function doUpdate() { + + var form = $("#formSave"); + if (validateForm(form)) { + + // Get data + sendConfig(getData(form)); + + // Empty special fields + $(".pwrExpected").val(0); + $("input[name='pwrResetCalibration']"). + prop("checked", false). + iphoneStyle("refresh"); + $("input[name='pwrResetE']"). + prop("checked", false). + iphoneStyle("refresh"); + + // Change handling + numChanged = 0; + setTimeout(function() { + + var response; + + if (numReboot > 0) { + response = window.confirm("You have to reboot the board for the changes to take effect, do you want to do it now?"); + if (response) { doReboot(false); } + } else if (numReconnect > 0) { + response = window.confirm("You have to reconnect to the WiFi for the changes to take effect, do you want to do it now?"); + if (response) { doReconnect(false); } + } else if (numReload > 0) { + response = window.confirm("You have to reload the page to see the latest changes, do you want to do it now?"); + if (response) { doReload(0); } + } + + resetOriginals(); + + }, 1000); - if (ask) { - var response = window.confirm("Are you sure you want to disconnect from the current WIFI network?"); - if (response == false) return false; } - websock.send(JSON.stringify({'action': 'reconnect'})); - doReload(5000); return false; } function doBackup() { - document.getElementById('downloader').src = webhost + 'config'; + document.getElementById("downloader").src = urls.config.href; return false; } function onFileUpload(event) { var inputFiles = this.files; - if (inputFiles == undefined || inputFiles.length == 0) return false; + if (typeof inputFiles === "undefined" || inputFiles.length === 0) { + return false; + } var inputFile = inputFiles[0]; this.value = ""; var response = window.confirm("Previous settings will be overwritten. Are you sure you want to restore this settings?"); - if (response == false) return false; + if (!response) { + return false; + } var reader = new FileReader(); reader.onload = function(e) { var data = getJson(e.target.result); if (data) { - websock.send(JSON.stringify({'action': 'restore', 'data': data})); + sendAction("restore", data); } else { - alert(messages[4]); + window.alert(messages[4]); } }; reader.readAsText(inputFile); @@ -362,7 +521,7 @@ function onFileUpload(event) { } function doRestore() { - if (typeof window.FileReader !== 'function') { + if (typeof window.FileReader !== "function") { alert("The file API isn't supported on this browser yet."); } else { $("#uploader").click(); @@ -370,9 +529,45 @@ function doRestore() { return false; } +function doFactoryReset() { + var response = window.confirm("Are you sure you want to restore to factory settings?"); + if (response === false) { + return false; + } + websock.send(JSON.stringify({"action": "factory_reset"})); + doReload(5000); + return false; +} + function doToggle(element, value) { - var relayID = parseInt(element.attr("data")); - websock.send(JSON.stringify({'action': 'relay', 'data': { 'id': relayID, 'status': value ? 1 : 0 }})); + var id = parseInt(element.attr("data"), 10); + sendAction("relay", {id: id, status: value ? 1 : 0 }); + return false; +} + +function doScan() { + $("#scanResult").html(""); + $("div.scan.loading").show(); + sendAction("scan", {}); + return false; +} + +function doHAConfig() { + $("#haConfig").html(""); + sendAction("haconfig", {}); + return false; +} + +function doDebugCommand() { + var el = $("input[name='dbgcmd']"); + var command = el.val(); + el.val(""); + sendAction("dbgcmd", {command: command}); + return false; +} + +function doDebugClear() { + $("#weblog").text(""); return false; } @@ -380,50 +575,53 @@ function doToggle(element, value) { // Visualization // ----------------------------------------------------------------------------- +function toggleMenu() { + $("#layout").toggleClass("active"); + $("#menu").toggleClass("active"); + $("#menuLink").toggleClass("active"); +} + function showPanel() { $(".panel").hide(); - $("#" + $(this).attr("data")).show(); - if ($("#layout").hasClass('active')) toggleMenu(); - $("input[type='checkbox']").iphoneStyle("calculateDimensions").iphoneStyle("refresh"); -}; - -function toggleMenu() { - $("#layout").toggleClass('active'); - $("#menu").toggleClass('active'); - $("#menuLink").toggleClass('active'); + if ($("#layout").hasClass("active")) { toggleMenu(); } + $("#" + $(this).attr("data")).show(). + find("input[type='checkbox']"). + iphoneStyle("calculateDimensions"). + iphoneStyle("refresh"); } // ----------------------------------------------------------------------------- -// Domoticz +// Relays & magnitudes mapping // ----------------------------------------------------------------------------- -function createRelayIdxs(data) { +function createRelayList(data, container, template_name) { - var current = $("#domoticzRelays > div").length; - if (current > 0) return; + var current = $("#" + container + " > div").length; + if (current > 0) { return; } - var template = $("#relayIdxTemplate .pure-g")[0]; - for (var i=0; i div").length; - if (current > 0) return; + var current = $("#" + container + " > div").length; + if (current > 0) { return; } - var template = $("#magnitudeIdxTemplate .pure-g")[0]; - for (var i=0; i div").length; if (numNetworks >= maxNetworks) { alert("Max number of networks reached"); - return; + return null; } var tabindex = 200 + numNetworks * 10; var template = $("#networkTemplate").children(); var line = $(template).clone(); $(line).find("input").each(function() { - $(this).attr("tabindex", tabindex++); + $(this).attr("tabindex", tabindex); + tabindex++; }); - $(line).find(".button-del-network").on('click', delNetwork); - $(line).find(".button-more-network").on('click', moreNetwork); + $(line).find(".button-del-network").on("click", delNetwork); + $(line).find(".button-more-network").on("click", moreNetwork); line.appendTo("#networks"); return line; } -function delNetwork() { +// ----------------------------------------------------------------------------- +// Relays scheduler +// ----------------------------------------------------------------------------- +function delSchedule() { var parent = $(this).parents(".pure-g"); $(parent).remove(); } -function moreNetwork() { +function moreSchedule() { var parent = $(this).parents(".pure-g"); - $(".more", parent).toggle(); + $("div.more", parent).toggle(); +} + +function addSchedule(event) { + var numSchedules = $("#schedules > div").length; + if (numSchedules >= maxSchedules) { + alert("Max number of schedules reached"); + return null; + } + var tabindex = 200 + numSchedules * 10; + var template = $("#scheduleTemplate").children(); + var line = $(template).clone(); + + var type = (1 === event.data.schType) ? "switch" : "light"; + + template = $("#" + type + "ActionTemplate").children(); + var actionLine = template.clone(); + $(line).find("#schActionDiv").append(actionLine); + + $(line).find("input").each(function() { + $(this).attr("tabindex", tabindex); + tabindex++; + }); + $(line).find(".button-del-schedule").on("click", delSchedule); + $(line).find(".button-more-schedule").on("click", moreSchedule); + line.appendTo("#schedules"); + + $(line).find("input[type='checkbox']"). + prop("checked", false). + iphoneStyle("calculateDimensions"). + iphoneStyle("refresh"); + + return line; } // ----------------------------------------------------------------------------- @@ -471,41 +715,50 @@ function moreNetwork() { function initRelays(data) { var current = $("#relays > div").length; - if (current > 0) return; + if (current > 0) { return; } var template = $("#relayTemplate .pure-g")[0]; for (var i=0; i").attr("value",i).text("Switch #" + i)); + } + } function initRelayConfig(data) { var current = $("#relayConfig > div").length; - if (current > 0) return; + if (current > 0) { return; } var template = $("#relayConfigTemplate").children(); - for (var i=0; i < data.length; i++) { + for (var i in data) { + var relay = data[i]; var line = $(template).clone(); - $("span.gpio", line).html(data[i].gpio); + $("span.gpio", line).html(relay.gpio); $("span.id", line).html(i); - $("select[name='relayBoot']", line).val(data[i].boot); - $("select[name='relayPulse']", line).val(data[i].pulse); - $("input[name='relayTime']", line).val(data[i].pulse_ms); - $("input[name='mqttGroup']", line).val(data[i].group); - $("select[name='mqttGroupInv']", line).val(data[i].group_inv); + $("select[name='relayBoot']", line).val(relay.boot); + $("select[name='relayPulse']", line).val(relay.pulse); + $("input[name='relayTime']", line).val(relay.pulse_ms); + $("input[name='mqttGroup']", line).val(relay.group); + $("select[name='mqttGroupInv']", line).val(relay.group_inv); + $("select[name='relayOnDisc']", line).val(relay.on_disc); line.appendTo("#relayConfig"); } @@ -519,27 +772,21 @@ function initMagnitudes(data) { // check if already initialized var done = $("#magnitudes > div").length; - if (done > 0) return; + if (done > 0) { return; } // add templates var template = $("#magnitudeTemplate").children(); - for (var i=0; i div").length; - if (done > 0) return; + if (done > 0) { return; } // add template var template = $("#colorRGBTemplate").children(); @@ -556,28 +803,44 @@ function initColorRGB() { line.appendTo("#colors"); // init color wheel - $('input[name="color"]').wheelColorPicker({ - sliders: 'wrgbp' - }).on('sliderup', function() { - var value = $(this).wheelColorPicker('getValue', 'css'); - websock.send(JSON.stringify({'action': 'color', 'data' : {'rgb': value}})); + $("input[name='color']").wheelColorPicker({ + sliders: "wrgbp" + }).on("sliderup", function() { + var value = $(this).wheelColorPicker("getValue", "css"); + sendAction("color", {rgb: value}); }); // init bright slider - $('#brightness').on("change", function() { + $("#brightness").on("change", function() { var value = $(this).val(); var parent = $(this).parents(".pure-g"); $("span", parent).html(value); - websock.send(JSON.stringify({'action': 'color', 'data' : {'brightness': value}})); + sendAction("color", {brightness: value}); }); } +function initCCT() { + + // check if already initialized + var done = $("#cct > div").length; + if (done > 0) { return; } + + $("#miredsTemplate").children().clone().appendTo("#cct"); + + $("#mireds").on("change", function() { + var value = $(this).val(); + var parent = $(this).parents(".pure-g"); + $("span", parent).html(value); + sendAction("mireds", {mireds: value}); + }); +} + function initColorHSV() { // check if already initialized var done = $("#colors > div").length; - if (done > 0) return; + if (done > 0) { return; } // add template var template = $("#colorHSVTemplate").children(); @@ -585,12 +848,12 @@ function initColorHSV() { line.appendTo("#colors"); // init color wheel - $('input[name="color"]').wheelColorPicker({ - sliders: 'whsvp' - }).on('sliderup', function() { - var color = $(this).wheelColorPicker('getColor'); - var value = parseInt(color.h * 360) + "," + parseInt(color.s * 100) + "," + parseInt(color.v * 100); - websock.send(JSON.stringify({'action': 'color', 'data' : {'hsv': value}})); + $("input[name='color']").wheelColorPicker({ + sliders: "whsvp" + }).on("sliderup", function() { + var color = $(this).wheelColorPicker("getColor"); + var value = parseInt(color.h * 360, 10) + "," + parseInt(color.s * 100, 10) + "," + parseInt(color.v * 100, 10); + sendAction("color", {hsv: value}); }); } @@ -599,7 +862,7 @@ function initChannels(num) { // check if already initialized var done = $("#channels > div").length > 0; - if (done) return; + if (done) { return; } // does it have color channels? var colors = $("#colors > div").length > 0; @@ -608,36 +871,67 @@ function initChannels(num) { var max = num; if (colors) { max = num % 3; - if ((max > 0) & useWhite) max--; + if ((max > 0) & useWhite) { + max--; + if (useCCT) { + max--; + } + } } var start = num - max; + var onChannelSliderChange = function() { + var id = $(this).attr("data"); + var value = $(this).val(); + var parent = $(this).parents(".pure-g"); + $("span", parent).html(value); + sendAction("channel", {id: id, value: value}); + }; + // add templates + var i = 0; var template = $("#channelTemplate").children(); - for (var i=0; i").attr("value",i).text("Channel #" + i)); + } + } // ----------------------------------------------------------------------------- // RFBridge // ----------------------------------------------------------------------------- +function rfbLearn() { + var parent = $(this).parents(".pure-g"); + var input = $("input", parent); + sendAction("rfblearn", {id: input.attr("data-id"), status: input.attr("data-status")}); +} + +function rfbForget() { + var parent = $(this).parents(".pure-g"); + var input = $("input", parent); + sendAction("rfbforget", {id: input.attr("data-id"), status: input.attr("data-status")}); +} + +function rfbSend() { + var parent = $(this).parents(".pure-g"); + var input = $("input", parent); + sendAction("rfbsend", {id: input.attr("data-id"), status: input.attr("data-status"), data: input.val()}); +} + function addRfbNode() { var numNodes = $("#rfbNodes > legend").length; @@ -651,32 +945,14 @@ function addRfbNode() { $(this).attr("data-status", status ? 1 : 0); status = !status; }); - $(line).find(".button-rfb-learn").on('click', rfbLearn); - $(line).find(".button-rfb-forget").on('click', rfbForget); - $(line).find(".button-rfb-send").on('click', rfbSend); + $(line).find(".button-rfb-learn").on("click", rfbLearn); + $(line).find(".button-rfb-forget").on("click", rfbForget); + $(line).find(".button-rfb-send").on("click", rfbSend); line.appendTo("#rfbNodes"); return line; } -function rfbLearn() { - var parent = $(this).parents(".pure-g"); - var input = $("input", parent); - websock.send(JSON.stringify({'action': 'rfblearn', 'data' : {'id' : input.attr("data-id"), 'status': input.attr("data-status")}})); -} - -function rfbForget() { - var parent = $(this).parents(".pure-g"); - var input = $("input", parent); - websock.send(JSON.stringify({'action': 'rfbforget', 'data' : {'id' : input.attr("data-id"), 'status': input.attr("data-status")}})); -} - -function rfbSend() { - var parent = $(this).parents(".pure-g"); - var input = $("input", parent); - websock.send(JSON.stringify({'action': 'rfbsend', 'data' : {'id' : input.attr("data-id"), 'status': input.attr("data-status"), 'data': input.val()}})); -} - // ----------------------------------------------------------------------------- // Processing // ----------------------------------------------------------------------------- @@ -689,7 +965,7 @@ function processData(data) { if ("app_version" in data) { title = title + " " + data.app_version; } - $(".pure-menu-heading").html(title); + $("span[name=title]").html(title); if ("hostname" in data) { title = data.hostname + " - " + title; } @@ -698,22 +974,25 @@ function processData(data) { Object.keys(data).forEach(function(key) { + var i; + var value = data[key]; + // --------------------------------------------------------------------- // Web mode // --------------------------------------------------------------------- - if (key == "webMode") { - password = data.webMode == 1; - $("#layout").toggle(data.webMode == 0); - $("#password").toggle(data.webMode == 1); + if ("webMode" === key) { + password = (1 === value); + $("#layout").toggle(!password); + $("#password").toggle(password); } // --------------------------------------------------------------------- // Actions // --------------------------------------------------------------------- - if (key == "action") { - if (data.action == "reload") doReload(1000); + if ("action" === key) { + if ("reload" === data.action) { doReload(1000); } return; } @@ -721,16 +1000,20 @@ function processData(data) { // RFBridge // --------------------------------------------------------------------- - if (key == "rfbCount") { - for (var i=0; i 0 && position == key.length - 7) { + if (position > 0 && position === key.length - 7) { var module = key.slice(0,-7); - $(".module-" + module).show(); + $(".module-" + module).css("display", "inherit"); return; } - // Pre-process - if (key == "network") { - data.network = data.network.toUpperCase(); + if ("deviceip" === key) { + var a_href = $("span[name='" + key + "']").parent(); + a_href.attr("href", "http://" + value); + a_href.next().attr("href", "telnet://" + value); } - if (key == "mqttStatus") { - data.mqttStatus = data.mqttStatus ? "CONNECTED" : "NOT CONNECTED"; + + if ("now" === key) { + now = value; + return; + } + + if ("free_size" === key) { + free_size = parseInt(value, 10); + } + + // Pre-process + if ("mqttStatus" === key) { + value = value ? "CONNECTED" : "NOT CONNECTED"; } - if (key == "ntpStatus") { - data.ntpStatus = data.ntpStatus ? "SYNC'D" : "NOT SYNC'D"; + if ("ntpStatus" === key) { + value = value ? "SYNC'D" : "NOT SYNC'D"; } - if (key == "uptime") { - var uptime = parseInt(data[key]); - var seconds = uptime % 60; uptime = parseInt(uptime / 60); - var minutes = uptime % 60; uptime = parseInt(uptime / 60); - var hours = uptime % 24; uptime = parseInt(uptime / 24); + if ("uptime" === key) { + ago = 0; + var uptime = parseInt(value, 10); + var seconds = uptime % 60; uptime = parseInt(uptime / 60, 10); + var minutes = uptime % 60; uptime = parseInt(uptime / 60, 10); + var hours = uptime % 24; uptime = parseInt(uptime / 24, 10); var days = uptime; - data[key] = days + 'd ' + zeroPad(hours, 2) + 'h ' + zeroPad(minutes, 2) + 'm ' + zeroPad(seconds, 2) + 's'; + value = days + "d " + zeroPad(hours, 2) + "h " + zeroPad(minutes, 2) + "m " + zeroPad(seconds, 2) + "s"; } // --------------------------------------------------------------------- // Matching // --------------------------------------------------------------------- + var pre; + var post; + // Look for INPUTs - var element = $("input[name=" + key + "]"); - if (element.length > 0) { - if (element.attr('type') == 'checkbox') { - element - .prop("checked", data[key]) - .iphoneStyle("refresh"); - } else if (element.attr('type') == 'radio') { - element.val([data[key]]); + var input = $("input[name='" + key + "']"); + if (input.length > 0) { + if (input.attr("type") === "checkbox") { + input. + prop("checked", value). + iphoneStyle("refresh"); + } else if (input.attr("type") === "radio") { + input.val([value]); } else { - var pre = element.attr("pre") || ""; - var post = element.attr("post") || ""; - element.val(pre + data[key] + post); + pre = input.attr("pre") || ""; + post = input.attr("post") || ""; + input.val(pre + value + post); } - return; } // Look for SPANs - var element = $("span[name=" + key + "]"); - if (element.length > 0) { - var pre = element.attr("pre") || ""; - var post = element.attr("post") || ""; - element.html(pre + data[key] + post); - return; + var span = $("span[name='" + key + "']"); + if (span.length > 0) { + pre = span.attr("pre") || ""; + post = span.attr("post") || ""; + span.html(pre + value + post); } // Look for SELECTs - var element = $("select[name=" + key + "]"); - if (element.length > 0) { - element.val(data[key]); - return; + var select = $("select[name='" + key + "']"); + if (select.length > 0) { + select.val(value); } }); // Auto generate an APIKey if none defined yet - if ($("input[name='apiKey']").val() == "") { + if ($("input[name='apiKey']").val() === "") { generateAPIKey(); } @@ -941,9 +1313,9 @@ function processData(data) { function hasChanged() { var newValue, originalValue; - if ($(this).attr('type') == 'checkbox') { - newValue = $(this).prop("checked") - originalValue = $(this).attr("original") == "true"; + if ($(this).attr("type") === "checkbox") { + newValue = $(this).prop("checked"); + originalValue = ($(this).attr("original") === "true"); } else { newValue = $(this).val(); originalValue = $(this).attr("original"); @@ -951,95 +1323,130 @@ function hasChanged() { var hasChanged = $(this).attr("hasChanged") || 0; var action = $(this).attr("action"); - if (typeof originalValue == 'undefined') return; - if (action == 'none') return; + if (typeof originalValue === "undefined") { return; } + if ("none" === action) { return; } - if (newValue != originalValue) { - if (hasChanged == 0) { + if (newValue !== originalValue) { + if (0 === hasChanged) { ++numChanged; - if (action == "reconnect") ++numReconnect; - if (action == "reboot") ++numReboot; - if (action == "reload") ++numReload; + if ("reconnect" === action) { ++numReconnect; } + if ("reboot" === action) { ++numReboot; } + if ("reload" === action) { ++numReload; } $(this).attr("hasChanged", 1); } } else { - if (hasChanged == 1) { + if (1 === hasChanged) { --numChanged; - if (action == "reconnect") --numReconnect; - if (action == "reboot") --numReboot; - if (action == "reload") --numReload; + if ("reconnect" === action) { --numReconnect; } + if ("reboot" === action) { --numReboot; } + if ("reload" === action) { --numReload; } $(this).attr("hasChanged", 0); } } } -function resetOriginals() { - $("input,select").each(function() { - $(this).attr("original", $(this).val()); - }) - numReboot = numReconnect = numReload = 0; -} - // ----------------------------------------------------------------------------- // Init & connect // ----------------------------------------------------------------------------- -function connect(host) { +function initUrls(root) { + + var paths = ["ws", "upgrade", "config", "auth"]; - if (typeof host === 'undefined') { - host = window.location.href.replace('#', ''); + urls["root"] = root; + paths.forEach(function(path) { + urls[path] = new URL(path, root); + urls[path].protocol = root.protocol; + }); + + if (root.protocol == "https:") { + urls.ws.protocol = "wss:"; } else { - if (host.indexOf("http") != 0) { - host = 'http://' + host + '/'; - } + urls.ws.protocol = "ws:"; } - if (host.indexOf("http") != 0) return; - webhost = host; - wshost = host.replace('http', 'ws') + 'ws'; +} - if (websock) websock.close(); - websock = new WebSocket(wshost); - websock.onmessage = function(evt) { - var data = getJson(evt.data); - if (data) processData(data); - }; +function connectToURL(url) { + + initUrls(url); + + $.ajax({ + 'method': 'GET', + 'url': urls.auth.href, + 'xhrFields': { 'withCredentials': true } + }).done(function(data) { + if (websock) { websock.close(); } + websock = new WebSocket(urls.ws.href); + websock.onmessage = function(evt) { + var data = getJson(evt.data.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")); + if (data) { + processData(data); + } + }; + }).fail(function() { + // Nothing to do, reload page and retry + }); + +} + +function connect(host) { + if (!host.startsWith("http:") && !host.startsWith("https:")) { + host = "http://" + host; + } + connectToURL(new URL(host)); +} + +function connectToCurrentURL() { + connectToURL(new URL(window.location)); } $(function() { initMessages(); - - $("#menuLink").on('click', toggleMenu); - $(".pure-menu-link").on('click', showPanel); - $('progress').attr({ value: 0, max: 100 }); - - $(".button-update").on('click', doUpdate); - $(".button-update-password").on('click', doUpdatePassword); - $(".button-reboot").on('click', doReboot); - $(".button-reconnect").on('click', doReconnect); - $(".button-settings-backup").on('click', doBackup); - $(".button-settings-restore").on('click', doRestore); - $('#uploader').on('change', onFileUpload); - $(".button-upgrade").on('click', doUpgrade); - - $(".button-apikey").on('click', generateAPIKey); - $(".button-upgrade-browse").on('click', function() { + loadTimeZones(); + setInterval(function() { keepTime(); }, 1000); + + $("#menuLink").on("click", toggleMenu); + $(".pure-menu-link").on("click", showPanel); + $("progress").attr({ value: 0, max: 100 }); + + $(".button-update").on("click", doUpdate); + $(".button-update-password").on("click", doUpdatePassword); + $(".button-reboot").on("click", doReboot); + $(".button-reconnect").on("click", doReconnect); + $(".button-wifi-scan").on("click", doScan); + $(".button-ha-config").on("click", doHAConfig); + $(".button-dbgcmd").on("click", doDebugCommand); + $("input[name='dbgcmd']").enterKey(doDebugCommand); + $(".button-dbg-clear").on("click", doDebugClear); + $(".button-settings-backup").on("click", doBackup); + $(".button-settings-restore").on("click", doRestore); + $(".button-settings-factory").on("click", doFactoryReset); + $("#uploader").on("change", onFileUpload); + $(".button-upgrade").on("click", doUpgrade); + + $(".button-apikey").on("click", generateAPIKey); + $(".button-upgrade-browse").on("click", function() { $("input[name='upgrade']")[0].click(); return false; }); $("input[name='upgrade']").change(function (){ - var fileName = $(this).val(); - $("input[name='filename']").val(fileName.replace(/^.*[\\\/]/, '')); + var file = this.files[0]; + $("input[name='filename']").val(file.name); }); - $(".button-add-network").on('click', function() { + $(".button-add-network").on("click", function() { $(".more", addNetwork()).toggle(); }); + $(".button-add-switch-schedule").on("click", { schType: 1 }, addSchedule); + $(".button-add-light-schedule").on("click", { schType: 2 }, addSchedule); - $(document).on('change', 'input', hasChanged); - $(document).on('change', 'select', hasChanged); + $(document).on("change", "input", hasChanged); + $(document).on("change", "select", hasChanged); - connect(); + // don't autoconnect when opening from filesystem + if (window.location.protocol === "file:") { return; } + connectToCurrentURL(); }); diff --git a/code/html/favicon.ico b/code/html/favicon.ico index ee8bae72..eeafbe44 100644 Binary files a/code/html/favicon.ico and b/code/html/favicon.ico differ diff --git a/code/html/images/border-off.png b/code/html/images/border-off.png deleted file mode 100644 index 6bfa573b..00000000 Binary files a/code/html/images/border-off.png and /dev/null differ diff --git a/code/html/images/border-on.png b/code/html/images/border-on.png deleted file mode 100644 index 4b9596ee..00000000 Binary files a/code/html/images/border-on.png and /dev/null differ diff --git a/code/html/images/handle-center.png b/code/html/images/handle-center.png deleted file mode 100644 index d280d61f..00000000 Binary files a/code/html/images/handle-center.png and /dev/null differ diff --git a/code/html/images/handle-left.png b/code/html/images/handle-left.png deleted file mode 100644 index 8eacd8d2..00000000 Binary files a/code/html/images/handle-left.png and /dev/null differ diff --git a/code/html/images/handle-right.png b/code/html/images/handle-right.png deleted file mode 100644 index 2eaf8b2c..00000000 Binary files a/code/html/images/handle-right.png and /dev/null differ diff --git a/code/html/images/label-off.png b/code/html/images/label-off.png deleted file mode 100644 index 1e2faaea..00000000 Binary files a/code/html/images/label-off.png and /dev/null differ diff --git a/code/html/images/label-on.png b/code/html/images/label-on.png deleted file mode 100644 index 888a11b6..00000000 Binary files a/code/html/images/label-on.png and /dev/null differ diff --git a/code/html/images/loading.gif b/code/html/images/loading.gif new file mode 100644 index 00000000..704b875f Binary files /dev/null and b/code/html/images/loading.gif differ diff --git a/code/html/index.html b/code/html/index.html index b1cf613b..57ee7740 100644 --- a/code/html/index.html +++ b/code/html/index.html @@ -8,12 +8,12 @@ - - - - + + + + + - @@ -51,7 +51,8 @@ - +
+ @@ -65,14 +66,15 @@
- + @@ -324,10 +366,10 @@
Define how the different switches should be synchronized.
@@ -352,15 +394,15 @@
-
+
-
Use color picker for the first 3 channels as RGB.
Will only work if the device has at least 3 dimmable channels.
Reload the page to update the web interface.
+
Use the first three channels as RGB channels. This will also enable the color picker in the web UI. Will only work if the device has at least 3 dimmable channels.
Reload the page to update the web interface.
-
+
@@ -368,37 +410,60 @@
-
+
-
Use forth dimmable channel as white when first 3 have the same RGB value.
Will only work if the device has at least 4 dimmable channels.
Reload the page to update the web interface.
+
Use forth dimmable channel as (cold) white light calculated out of the RGB values.
Will only work if the device has at least 4 dimmable channels.
Enabling this will render useless the "Channel 4" slider in the status page.
Reload the page to update the web interface.
-
-
+ +
+
+
+
Use fifth dimmable channel as warm white light and the forth dimmable channel as cold white.
Will only work if the device has at least 5 dimmable channels and "white channel" above is also ON.
Enabling this will render useless the "Channel 5" slider in the status page.
Reload the page to update the web interface.
+
+ +
+ +
Use gamma correction for RGB channels.
Will only work if "use colorpicker" above is also ON.
-
-
+ +
Use CSS style to report colors to MQTT and REST API.
Red will be reported as "#FF0000" if ON, otherwise "255,0,0"
-
-
+ +
If enabled color changes will be smoothed.
+
+ +
+
+
+
Time in millisecons to transition from one color to another.
+
+ +
+
+
+
+
Sync color between different lights.
+
+
@@ -414,6 +479,13 @@
+
+ +
+
+
+
+
@@ -440,12 +512,17 @@
-
+ +
+
+ +
+
-
+
@@ -468,7 +545,7 @@
-
+
@@ -477,7 +554,7 @@
-
+
@@ -488,18 +565,14 @@
This name address of the NoFUSS server for automatic remote updates (see https://bitbucket.org/xoseperez/nofuss).
-
- -
-
-
-
+
The device has bytes available for OTA updates. If your image is larger than this consider doing a two-step update.
+
@@ -519,15 +592,60 @@
-
+ General + +
+ +
+
+
+
+ ESPurna will scan for visible WiFi SSIDs and try to connect to networks defined below in order of signal strength, even if multiple AP share the same SSID. + When disabled, ESPurna will try to connect to the networks in the same order they are listed below. + Disable this option if you are connecting to a single access point (or router) or to a hidden SSID. + +
+
+ +
+
+ +
+
+ Networks + +
+
+
+ +
+

SCHEDULE

+

Turn switches ON and OFF based on the current time.

+
+ +
+ +
+ +
+ + + + +
+ +
+ +
+
@@ -540,33 +658,43 @@
-
+
- +
- +
- +
- + +
+ +
+ + +
+
+
+ If left empty the firmware will generate a client ID based on the serial number of the chip. +
- @@ -575,22 +703,22 @@
-
+
- +
-
+
- +
This is the fingerprint for the SSL certificate of the server.
@@ -602,14 +730,15 @@
- +
- This is the root topic for this device. A trailing slash will be added if not preset. The {identifier} placeholder will be replaced by the device hostname.
+ This is the root topic for this device. The {hostname} and {mac} placeholders will be replaced by the device hostname and MAC address.
- <root>/relay/#/set Send a 0 or a 1 as a payload to this topic to switch it on or off. You can also send a 2 to toggle its current state. Replace # with the switch ID (starting from 0). If the board has only one switch it will be 0.
- - <root>/color/set Set the color using this topic, your can either send an "#RRGGBB" value or "RRR,GGG,BBB".
- - <root>/brightness/set Set the brighness using a value from 0 to 255.
- - <root>/channel/#/set Set the value for a single color channel (from 0 to 255). Replace # with the channel ID (starting from 0 and up to 4 for RGBWC lights).
+ - <root>/rgb/set Set the color using this topic, your can either send an "#RRGGBB" value or "RRR,GGG,BBB" (0-255 each).
+ - <root>/hsv/set Set the color using hue (0-360), saturation (0-100) and value (0-100) values, comma separated.
+ - <root>/brightness/set Set the brighness (0-255).
+ - <root>/channel/#/set Set the value for a single color channel (0-255). Replace # with the channel ID (starting from 0 and up to 4 for RGBWC lights).
- <root>/mired/set Set the temperature color in mired.
- <root>/status The device will report a 1 to this topic every few minutes. Upon MQTT disconnecting this will be set to 0.
- Other values reported (depending on the build) are: firmware and version, hostname, IP, MAC, signal strenth (RSSI), uptime (in seconds), free heap and power supply. @@ -617,14 +746,14 @@
-
-
+ +
All messages (except the device status) will be included in a JSON payload along with the timestamp and hostname and sent under the <root>/data topic.
Messages will be queued and sent after 100ms, so different messages could be merged into a single payload.
- Subscribtions will still be done to single topics. + Subscriptions will still be done to single topics.
@@ -645,31 +774,31 @@
- - + +
- - + +
- - + +
- -
-
-
-
Set to 0 for UTC time
+ +
-
-
+ +
@@ -693,18 +822,10 @@ General
-
+
-
- -
-
-
-
Skip messages from the same IDX for these many seconds
-
-
@@ -721,9 +842,103 @@
Set IDX to 0 to disable notifications from that component.
-
+
-
+
+ +
+
+ +
+ +
+ +
+

HOME ASSISTANT

+

+ Add this device to your Home Assistant. +

+
+ +
+
+ + Discover + +
+ +
+
+
+
+ Home Assistant auto-discovery feature. Enable and save to add the device to your HA console. + When using a colour light you might want to disable CSS style so Home Assistant can parse the color. +
+
+ +
+ + +
+ + Configuration + +
+ +
+
+
+ These are the settings you should copy to your Home Assistant "configuration.yaml" file. + If any of the sections below (switch, light, sensor) already exists, do not duplicate it, + simply copy the contents of the section below the ones already present. +
+
+
+ +
+ + +
+
+ +
+ + + +
+ +
+

THINGSPEAK

+

+ Send your sensors data to Thingspeak. +

+
+ +
+ +
+ + General + +
+ +
+
+ +
+ + +
+ + Sensors & actuators + +
+
Enter the field number to send each data to, 0 disable notifications from that component.
+
+ +
+ +
@@ -744,7 +959,7 @@
-
+
@@ -778,6 +993,38 @@
+
+ +
+

DEBUG LOG

+

+ Shows debug messages from the device +

+
+ +
+ +
+ +
+
+ Write a command and click send to execute it on the device. The output will be shown in the debug text area below. +
+ +
+
+ +
+ +
+
+ +
+ +
+ +
+
@@ -820,6 +1067,22 @@
+
+ + +
+ +
+ + +
+
+
+
+
+ Humidity correction value is added to the measured value which may be inaccurate due to many factors. The value can be negative. +
+
+ + Energy monitor
- +
Mains voltage in your system (in V).
-
+
- +
-
In Ampers (A). If you are using a pure resistive load like a bulb this will the ratio between the two previous values, i.e. power / voltage. You can also use a current clamp around one fo the power wires to get this value.
+
In Amperes (A). If you are using a pure resistive load like a bulb, this will be the ratio between the two previous values, i.e. power / voltage. You can also use a current clamp around one of the power wires to get this value.
-
+
- +
In Volts (V). Enter your the nominal AC voltage for your household or facility, or use multimeter to get this value.
-
+
- +
In Watts (W). Calibrate your sensor connecting a pure resistive load (like a bulb) and enter here the its nominal power or use a multimeter.
-
-
+
+
Move this switch to ON and press "Save" to revert to factory calibration values.
+
+ +
+
+
+
Move this switch to ON and press "Save" to set energy count to 0.
+
+
@@ -884,12 +1165,14 @@
-

RFBRIDGE

+

RADIO FREQUENCY

- Sonoff 433 RF Bridge Configuration

- To learn a new code click LEARN, the Sonoff RFBridge will beep, then press a button on the remote, the RFBridge will then double beep and the new code should show up. If the device double beeps but the code does not update it has not been properly learnt. Keep trying.

- Modify or create new codes manually (all codes must be 18 characters long) and then click SAVE to store them in the device memory. If your controlled device uses the same code to switch ON and OFF, learn the code with the ON button and copy paste it to the OFF input box, then click SAVE on the last one to store the value.

+ Sonoff 433 RF Bridge & RF Link Configuration

+ This page allows you to configure the RF codes for the Sonoff RFBridge 433 and also for a basic RF receiver.

+ To learn a new code click LEARN (the Sonoff RFBridge will beep) then press a button on the remote, the new code should show up (and the RFBridge will double beep). If the device double beeps but the code does not update it has not been properly learnt. Keep trying.

+ Modify or create new codes manually and then click SAVE to store them in the device memory. If your controlled device uses the same code to switch ON and OFF, learn the code with the ON button and copy paste it to the OFF input box, then click SAVE on the last one to store the value.

Delete any code clicking the FORGET button. +

You can also specify 116-chars long RAW codes. Raw codes require a specific firmware for for the EFM8BB1.

@@ -935,42 +1218,99 @@
-
+
- +
Leave empty for DNS negotiation
- +
Set when using a static IP
- +
Usually 255.255.255.0 for /24 networks
- +
Set the Domain Name Server IP to use when using a static IP
- +
+
+ +
+ + +
+ +
 h
+
+
+ +
 m
+
+
+ + +
+ + +
+ +
+
 1 for Monday, 2 for Tuesday...
+ +
+
+ + +
+ +
+ +
+
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ + +
+
-
+
@@ -983,7 +1323,7 @@ - +
@@ -1009,19 +1349,42 @@
+
+
+ +
-
+
-
+
-
+
-
+
+
+
+
+ +
+
+ +
+
+
+ +
+
+ +
@@ -1054,6 +1417,14 @@
+
+
+ + + +
+
+
@@ -1070,10 +1441,10 @@ - - + - + + diff --git a/code/html/pure-1.0.0.min.css b/code/html/pure-1.0.0.min.css deleted file mode 100644 index e3ddfbf0..00000000 --- a/code/html/pure-1.0.0.min.css +++ /dev/null @@ -1,11 +0,0 @@ -/*! -Pure v1.0.0 -Copyright 2013 Yahoo! -Licensed under the BSD License. -https://github.com/yahoo/pure/blob/master/LICENSE.md -*/ -/*! -normalize.css v^3.0 | MIT License | git.io/normalize -Copyright (c) Nicolas Gallagher and Jonathan Neal -*/ -/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */.pure-button:focus,a:active,a:hover{outline:0}.pure-table,table{border-collapse:collapse;border-spacing:0}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}abbr[title]{border-bottom:1px dotted}b,optgroup,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre,textarea{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}.pure-button,input{line-height:normal}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}.pure-button,.pure-form input:not([type]),.pure-menu{box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend,td,th{padding:0}legend{border:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-flow:row wrap;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-align-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){table .pure-g{display:block}}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u,.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto;display:inline-block;zoom:1}.pure-g [class*=pure-u]{font-family:sans-serif}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}.pure-button{display:inline-block;zoom:1;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-.43em}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:transparent;background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{filter:alpha(opacity=90);background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000\9}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto;margin:0;border-radius:0;border-right:1px solid #111;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=tel],.pure-form input[type=color],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=text],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px}.pure-form input[type=color]{padding:.2em .5em}.pure-form input:not([type]):focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=text]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=checkbox]:focus,.pure-form input[type=radio]:focus{outline:#129FEA auto 1px}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input:not([type])[disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=text][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input:not([type]),.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked input[type=file],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=text],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-aligned .pure-help-inline,.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline{display:inline-block;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-3-4{width:75%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=tel],.pure-form input[type=color],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=text],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=tel],.pure-group input[type=color],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=text]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;zoom:1;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar{display:none}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-disabled,.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected .pure-menu-link,.pure-menu-selected .pure-menu-link:visited{color:#000}.pure-table{empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td,.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} \ No newline at end of file diff --git a/code/html/pure-grids-responsive-1.0.0.min.css b/code/html/pure-grids-responsive-1.0.0.min.css deleted file mode 100644 index e10c0003..00000000 --- a/code/html/pure-grids-responsive-1.0.0.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! -Pure v1.0.0 -Copyright 2013 Yahoo! -Licensed under the BSD License. -https://github.com/yahoo/pure/blob/master/LICENSE.md -*/ -@media screen and (min-width:35.5em){.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-1-12,.pure-u-sm-1-2,.pure-u-sm-1-24,.pure-u-sm-1-3,.pure-u-sm-1-4,.pure-u-sm-1-5,.pure-u-sm-1-6,.pure-u-sm-1-8,.pure-u-sm-10-24,.pure-u-sm-11-12,.pure-u-sm-11-24,.pure-u-sm-12-24,.pure-u-sm-13-24,.pure-u-sm-14-24,.pure-u-sm-15-24,.pure-u-sm-16-24,.pure-u-sm-17-24,.pure-u-sm-18-24,.pure-u-sm-19-24,.pure-u-sm-2-24,.pure-u-sm-2-3,.pure-u-sm-2-5,.pure-u-sm-20-24,.pure-u-sm-21-24,.pure-u-sm-22-24,.pure-u-sm-23-24,.pure-u-sm-24-24,.pure-u-sm-3-24,.pure-u-sm-3-4,.pure-u-sm-3-5,.pure-u-sm-3-8,.pure-u-sm-4-24,.pure-u-sm-4-5,.pure-u-sm-5-12,.pure-u-sm-5-24,.pure-u-sm-5-5,.pure-u-sm-5-6,.pure-u-sm-5-8,.pure-u-sm-6-24,.pure-u-sm-7-12,.pure-u-sm-7-24,.pure-u-sm-7-8,.pure-u-sm-8-24,.pure-u-sm-9-24{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-sm-1-24{width:4.1667%}.pure-u-sm-1-12,.pure-u-sm-2-24{width:8.3333%}.pure-u-sm-1-8,.pure-u-sm-3-24{width:12.5%}.pure-u-sm-1-6,.pure-u-sm-4-24{width:16.6667%}.pure-u-sm-1-5{width:20%}.pure-u-sm-5-24{width:20.8333%}.pure-u-sm-1-4,.pure-u-sm-6-24{width:25%}.pure-u-sm-7-24{width:29.1667%}.pure-u-sm-1-3,.pure-u-sm-8-24{width:33.3333%}.pure-u-sm-3-8,.pure-u-sm-9-24{width:37.5%}.pure-u-sm-2-5{width:40%}.pure-u-sm-10-24,.pure-u-sm-5-12{width:41.6667%}.pure-u-sm-11-24{width:45.8333%}.pure-u-sm-1-2,.pure-u-sm-12-24{width:50%}.pure-u-sm-13-24{width:54.1667%}.pure-u-sm-14-24,.pure-u-sm-7-12{width:58.3333%}.pure-u-sm-3-5{width:60%}.pure-u-sm-15-24,.pure-u-sm-5-8{width:62.5%}.pure-u-sm-16-24,.pure-u-sm-2-3{width:66.6667%}.pure-u-sm-17-24{width:70.8333%}.pure-u-sm-18-24,.pure-u-sm-3-4{width:75%}.pure-u-sm-19-24{width:79.1667%}.pure-u-sm-4-5{width:80%}.pure-u-sm-20-24,.pure-u-sm-5-6{width:83.3333%}.pure-u-sm-21-24,.pure-u-sm-7-8{width:87.5%}.pure-u-sm-11-12,.pure-u-sm-22-24{width:91.6667%}.pure-u-sm-23-24{width:95.8333%}.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-24-24,.pure-u-sm-5-5{width:100%}}@media screen and (min-width:48em){.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-1-12,.pure-u-md-1-2,.pure-u-md-1-24,.pure-u-md-1-3,.pure-u-md-1-4,.pure-u-md-1-5,.pure-u-md-1-6,.pure-u-md-1-8,.pure-u-md-10-24,.pure-u-md-11-12,.pure-u-md-11-24,.pure-u-md-12-24,.pure-u-md-13-24,.pure-u-md-14-24,.pure-u-md-15-24,.pure-u-md-16-24,.pure-u-md-17-24,.pure-u-md-18-24,.pure-u-md-19-24,.pure-u-md-2-24,.pure-u-md-2-3,.pure-u-md-2-5,.pure-u-md-20-24,.pure-u-md-21-24,.pure-u-md-22-24,.pure-u-md-23-24,.pure-u-md-24-24,.pure-u-md-3-24,.pure-u-md-3-4,.pure-u-md-3-5,.pure-u-md-3-8,.pure-u-md-4-24,.pure-u-md-4-5,.pure-u-md-5-12,.pure-u-md-5-24,.pure-u-md-5-5,.pure-u-md-5-6,.pure-u-md-5-8,.pure-u-md-6-24,.pure-u-md-7-12,.pure-u-md-7-24,.pure-u-md-7-8,.pure-u-md-8-24,.pure-u-md-9-24{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-md-1-24{width:4.1667%}.pure-u-md-1-12,.pure-u-md-2-24{width:8.3333%}.pure-u-md-1-8,.pure-u-md-3-24{width:12.5%}.pure-u-md-1-6,.pure-u-md-4-24{width:16.6667%}.pure-u-md-1-5{width:20%}.pure-u-md-5-24{width:20.8333%}.pure-u-md-1-4,.pure-u-md-6-24{width:25%}.pure-u-md-7-24{width:29.1667%}.pure-u-md-1-3,.pure-u-md-8-24{width:33.3333%}.pure-u-md-3-8,.pure-u-md-9-24{width:37.5%}.pure-u-md-2-5{width:40%}.pure-u-md-10-24,.pure-u-md-5-12{width:41.6667%}.pure-u-md-11-24{width:45.8333%}.pure-u-md-1-2,.pure-u-md-12-24{width:50%}.pure-u-md-13-24{width:54.1667%}.pure-u-md-14-24,.pure-u-md-7-12{width:58.3333%}.pure-u-md-3-5{width:60%}.pure-u-md-15-24,.pure-u-md-5-8{width:62.5%}.pure-u-md-16-24,.pure-u-md-2-3{width:66.6667%}.pure-u-md-17-24{width:70.8333%}.pure-u-md-18-24,.pure-u-md-3-4{width:75%}.pure-u-md-19-24{width:79.1667%}.pure-u-md-4-5{width:80%}.pure-u-md-20-24,.pure-u-md-5-6{width:83.3333%}.pure-u-md-21-24,.pure-u-md-7-8{width:87.5%}.pure-u-md-11-12,.pure-u-md-22-24{width:91.6667%}.pure-u-md-23-24{width:95.8333%}.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-24-24,.pure-u-md-5-5{width:100%}}@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-12,.pure-u-lg-1-2,.pure-u-lg-1-24,.pure-u-lg-1-3,.pure-u-lg-1-4,.pure-u-lg-1-5,.pure-u-lg-1-6,.pure-u-lg-1-8,.pure-u-lg-10-24,.pure-u-lg-11-12,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-2-24,.pure-u-lg-2-3,.pure-u-lg-2-5,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24,.pure-u-lg-3-24,.pure-u-lg-3-4,.pure-u-lg-3-5,.pure-u-lg-3-8,.pure-u-lg-4-24,.pure-u-lg-4-5,.pure-u-lg-5-12,.pure-u-lg-5-24,.pure-u-lg-5-5,.pure-u-lg-5-6,.pure-u-lg-5-8,.pure-u-lg-6-24,.pure-u-lg-7-12,.pure-u-lg-7-24,.pure-u-lg-7-8,.pure-u-lg-8-24,.pure-u-lg-9-24{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%}.pure-u-lg-1-5{width:20%}.pure-u-lg-5-24{width:20.8333%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%}.pure-u-lg-7-24{width:29.1667%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%}.pure-u-lg-2-5{width:40%}.pure-u-lg-10-24,.pure-u-lg-5-12{width:41.6667%}.pure-u-lg-11-24{width:45.8333%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%}.pure-u-lg-13-24{width:54.1667%}.pure-u-lg-14-24,.pure-u-lg-7-12{width:58.3333%}.pure-u-lg-3-5{width:60%}.pure-u-lg-15-24,.pure-u-lg-5-8{width:62.5%}.pure-u-lg-16-24,.pure-u-lg-2-3{width:66.6667%}.pure-u-lg-17-24{width:70.8333%}.pure-u-lg-18-24,.pure-u-lg-3-4{width:75%}.pure-u-lg-19-24{width:79.1667%}.pure-u-lg-4-5{width:80%}.pure-u-lg-20-24,.pure-u-lg-5-6{width:83.3333%}.pure-u-lg-21-24,.pure-u-lg-7-8{width:87.5%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%}.pure-u-lg-23-24{width:95.8333%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-24-24,.pure-u-lg-5-5{width:100%}}@media screen and (min-width:80em){.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-1-12,.pure-u-xl-1-2,.pure-u-xl-1-24,.pure-u-xl-1-3,.pure-u-xl-1-4,.pure-u-xl-1-5,.pure-u-xl-1-6,.pure-u-xl-1-8,.pure-u-xl-10-24,.pure-u-xl-11-12,.pure-u-xl-11-24,.pure-u-xl-12-24,.pure-u-xl-13-24,.pure-u-xl-14-24,.pure-u-xl-15-24,.pure-u-xl-16-24,.pure-u-xl-17-24,.pure-u-xl-18-24,.pure-u-xl-19-24,.pure-u-xl-2-24,.pure-u-xl-2-3,.pure-u-xl-2-5,.pure-u-xl-20-24,.pure-u-xl-21-24,.pure-u-xl-22-24,.pure-u-xl-23-24,.pure-u-xl-24-24,.pure-u-xl-3-24,.pure-u-xl-3-4,.pure-u-xl-3-5,.pure-u-xl-3-8,.pure-u-xl-4-24,.pure-u-xl-4-5,.pure-u-xl-5-12,.pure-u-xl-5-24,.pure-u-xl-5-5,.pure-u-xl-5-6,.pure-u-xl-5-8,.pure-u-xl-6-24,.pure-u-xl-7-12,.pure-u-xl-7-24,.pure-u-xl-7-8,.pure-u-xl-8-24,.pure-u-xl-9-24{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xl-1-24{width:4.1667%}.pure-u-xl-1-12,.pure-u-xl-2-24{width:8.3333%}.pure-u-xl-1-8,.pure-u-xl-3-24{width:12.5%}.pure-u-xl-1-6,.pure-u-xl-4-24{width:16.6667%}.pure-u-xl-1-5{width:20%}.pure-u-xl-5-24{width:20.8333%}.pure-u-xl-1-4,.pure-u-xl-6-24{width:25%}.pure-u-xl-7-24{width:29.1667%}.pure-u-xl-1-3,.pure-u-xl-8-24{width:33.3333%}.pure-u-xl-3-8,.pure-u-xl-9-24{width:37.5%}.pure-u-xl-2-5{width:40%}.pure-u-xl-10-24,.pure-u-xl-5-12{width:41.6667%}.pure-u-xl-11-24{width:45.8333%}.pure-u-xl-1-2,.pure-u-xl-12-24{width:50%}.pure-u-xl-13-24{width:54.1667%}.pure-u-xl-14-24,.pure-u-xl-7-12{width:58.3333%}.pure-u-xl-3-5{width:60%}.pure-u-xl-15-24,.pure-u-xl-5-8{width:62.5%}.pure-u-xl-16-24,.pure-u-xl-2-3{width:66.6667%}.pure-u-xl-17-24{width:70.8333%}.pure-u-xl-18-24,.pure-u-xl-3-4{width:75%}.pure-u-xl-19-24{width:79.1667%}.pure-u-xl-4-5{width:80%}.pure-u-xl-20-24,.pure-u-xl-5-6{width:83.3333%}.pure-u-xl-21-24,.pure-u-xl-7-8{width:87.5%}.pure-u-xl-11-12,.pure-u-xl-22-24{width:91.6667%}.pure-u-xl-23-24{width:95.8333%}.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-24-24,.pure-u-xl-5-5{width:100%}} \ No newline at end of file diff --git a/code/html/checkboxes.css b/code/html/vendor/checkboxes.css similarity index 100% rename from code/html/checkboxes.css rename to code/html/vendor/checkboxes.css diff --git a/code/html/checkboxes.js b/code/html/vendor/checkboxes.js similarity index 81% rename from code/html/checkboxes.js rename to code/html/vendor/checkboxes.js index 42e1441b..a77b7703 100644 --- a/code/html/checkboxes.js +++ b/code/html/vendor/checkboxes.js @@ -1,4 +1,7 @@ // Generated by CoffeeScript 1.6.2 +/*eslint quotes: ["error", "double"]*/ +/*eslint-env es6*/ + (function() { var iOSCheckbox, matched, userAgent, __slice = [].slice; @@ -33,8 +36,10 @@ this.elem = $(elem); opts = $.extend({}, iOSCheckbox.defaults, options); for (key in opts) { - value = opts[key]; - this[key] = value; + if ({}.hasOwnProperty.call(opts, key)) { + value = opts[key]; + this[key] = value; + } } this.elem.data(this.dataName, this); this.wrapCheckboxWithDivs(); @@ -45,27 +50,27 @@ iOSCheckbox.prototype.calculateDimensions = function() { if (this.resizeHandle) { - this.optionallyResize('handle'); + this.optionallyResize("handle"); } if (this.resizeContainer) { - this.optionallyResize('container'); + this.optionallyResize("container"); } return this.initialPosition(); }; iOSCheckbox.prototype.isDisabled = function() { - return this.elem.is(':disabled'); + return this.elem.is(":disabled"); }; iOSCheckbox.prototype.wrapCheckboxWithDivs = function() { this.elem.wrap("
"); this.container = this.elem.parent(); this.offLabel = $("").appendTo(this.container); - this.offSpan = this.offLabel.children('span'); + this.offSpan = this.offLabel.children("span"); this.onLabel = $("").appendTo(this.container); this.onBorder = $("
").appendTo(this.container); this.offBorder = $("
").appendTo(this.container); - this.onSpan = this.onLabel.children('span'); + this.onSpan = this.onLabel.children("span"); this.handle = $("
").appendTo(this.container); this.handleCenter = $("
").appendTo(this.handle); this.handleRight = $("
").appendTo(this.handle); @@ -89,12 +94,12 @@ iOSCheckbox.prototype.optionallyResize = function(mode) { var newWidth, offLabelWidth, offSpan, onLabelWidth, onSpan; - onSpan = this.onLabel.find('span'); + onSpan = this.onLabel.find("span"); onLabelWidth = this._getDimension(onSpan, "width"); - onLabelWidth += parseInt(onSpan.css('padding-left'), 10); - offSpan = this.offLabel.find('span'); + onLabelWidth += parseInt(onSpan.css("padding-left"), 10); + offSpan = this.offLabel.find("span"); offLabelWidth = this._getDimension(offSpan, "width"); - offLabelWidth += parseInt(offSpan.css('padding-right'), 10); + offLabelWidth += parseInt(offSpan.css("padding-right"), 10); if (mode === "container") { newWidth = onLabelWidth > offLabelWidth ? onLabelWidth : offLabelWidth; newWidth += this._getDimension(this.handle, "width") + this.handleMargin; @@ -122,7 +127,7 @@ x = event.pageX || event.originalEvent.changedTouches[0].pageX; iOSCheckbox.currentlyClicking = this.handle; iOSCheckbox.dragStartPosition = x; - return iOSCheckbox.handleLeftOffset = parseInt(this.handle.css('left'), 10) || 0; + return iOSCheckbox.handleLeftOffset = parseInt(this.handle.css("left"), 10) || 0; }; iOSCheckbox.prototype.onDragMove = function(event, x) { @@ -164,14 +169,14 @@ } if (iOSCheckbox.dragging) { p = (x - iOSCheckbox.dragStartPosition) / this.rightSide; - this.elem.prop('checked', p >= 0.5).change(); + this.elem.prop("checked", p >= 0.5).change(); } else { - this.elem.prop('checked', !this.elem.prop('checked')).change(); + this.elem.prop("checked", !this.elem.prop("checked")).change(); } iOSCheckbox.currentlyClicking = null; iOSCheckbox.dragging = null; if (typeof this.onChange === "function") { - this.onChange(this.elem, this.elem.prop('checked')); + this.onChange(this.elem, this.elem.prop("checked")); } return this.didChange(); }; @@ -181,7 +186,7 @@ }; iOSCheckbox.prototype.didChange = function() { - var new_left; + var newLeft; if (this.isDisabled()) { this.container.addClass(this.disabledClass); @@ -189,18 +194,18 @@ } else { this.container.removeClass(this.disabledClass); } - new_left = this.elem.prop('checked') ? this.rightSide + 2 : 0; + newLeft = this.elem.prop("checked") ? this.rightSide + 2 : 0; this.handle.animate({ - left: new_left + left: newLeft }, this.duration); this.onLabel.animate({ - width: new_left + this.handleRadius + width: newLeft + this.handleRadius }, this.duration); this.offSpan.animate({ - marginRight: -new_left + marginRight: - newLeft }, this.duration); return this.onSpan.animate({ - marginLeft: new_left - this.rightSide + marginLeft: newLeft - this.rightSide }, this.duration); }; @@ -213,16 +218,16 @@ }; localMouseUp = function(event) { self.onGlobalUp.apply(self, arguments); - $(document).unbind('mousemove touchmove', localMouseMove); - return $(document).unbind('mouseup touchend', localMouseUp); + $(document).unbind("mousemove touchmove", localMouseMove); + return $(document).unbind("mouseup touchend", localMouseUp); }; this.elem.change(function() { return self.refresh(); }); - return this.container.bind('mousedown touchstart', function(event) { + return this.container.bind("mousedown touchstart", function(event) { self.onMouseDown.apply(self, arguments); - $(document).bind('mousemove touchmove', localMouseMove); - return $(document).bind('mouseup touchend', localMouseUp); + $(document).bind("mousemove touchmove", localMouseMove); + return $(document).bind("mouseup touchend", localMouseUp); }); }; @@ -241,7 +246,7 @@ offset -= 3; } this.rightSide = containerWidth - this._getDimension(this.handle, "width") - offset; - if (this.elem.is(':checked')) { + if (this.elem.is(":checked")) { this.handle.css({ left: this.rightSide }); @@ -292,17 +297,17 @@ iOSCheckbox.defaults = { duration: 200, - checkedLabel: 'ON', - uncheckedLabel: 'OFF', + checkedLabel: "ON", + uncheckedLabel: "OFF", resizeHandle: true, resizeContainer: true, - disabledClass: 'iPhoneCheckDisabled', - containerClass: 'iPhoneCheckContainer', - labelOnClass: 'iPhoneCheckLabelOn', - labelOffClass: 'iPhoneCheckLabelOff', - handleClass: 'iPhoneCheckHandle', - handleCenterClass: 'iPhoneCheckHandleCenter', - handleRightClass: 'iPhoneCheckHandleRight', + disabledClass: "iPhoneCheckDisabled", + containerClass: "iPhoneCheckContainer", + labelOnClass: "iPhoneCheckLabelOn", + labelOffClass: "iPhoneCheckLabelOff", + handleClass: "iPhoneCheckHandle", + handleCenterClass: "iPhoneCheckHandleCenter", + handleRightClass: "iPhoneCheckHandleRight", dragThreshold: 5, handleMargin: 15, handleRadius: 4, @@ -322,7 +327,7 @@ args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; dataName = (_ref = (_ref1 = args[0]) != null ? _ref1.dataName : void 0) != null ? _ref : iOSCheckbox.defaults.dataName; - _ref2 = this.filter(':checkbox'); + _ref2 = this.filter(":checkbox"); for (_i = 0, _len = _ref2.length; _i < _len; _i++) { checkbox = _ref2[_i]; existingControl = $(checkbox).data(dataName); @@ -346,14 +351,14 @@ } opts = $.extend({}, options, { resizeHandle: false, - disabledClass: 'iOSCheckDisabled', - containerClass: 'iOSCheckContainer', - labelOnClass: 'iOSCheckLabelOn', - labelOffClass: 'iOSCheckLabelOff', - handleClass: 'iOSCheckHandle', - handleCenterClass: 'iOSCheckHandleCenter', - handleRightClass: 'iOSCheckHandleRight', - dataName: 'iOSCheckbox' + disabledClass: "iOSCheckDisabled", + containerClass: "iOSCheckContainer", + labelOnClass: "iOSCheckLabelOn", + labelOffClass: "iOSCheckLabelOff", + handleClass: "iOSCheckHandle", + handleCenterClass: "iOSCheckHandleCenter", + handleRightClass: "iOSCheckHandleRight", + dataName: "iOSCheckbox" }); return this.iphoneStyle(opts); }; diff --git a/code/html/vendor/images/border-off.png b/code/html/vendor/images/border-off.png new file mode 100644 index 00000000..2163fb0d Binary files /dev/null and b/code/html/vendor/images/border-off.png differ diff --git a/code/html/vendor/images/border-on.png b/code/html/vendor/images/border-on.png new file mode 100644 index 00000000..2bce84f6 Binary files /dev/null and b/code/html/vendor/images/border-on.png differ diff --git a/code/html/vendor/images/handle-center.png b/code/html/vendor/images/handle-center.png new file mode 100644 index 00000000..49ceb533 Binary files /dev/null and b/code/html/vendor/images/handle-center.png differ diff --git a/code/html/vendor/images/handle-left.png b/code/html/vendor/images/handle-left.png new file mode 100644 index 00000000..9d9257d7 Binary files /dev/null and b/code/html/vendor/images/handle-left.png differ diff --git a/code/html/vendor/images/handle-right.png b/code/html/vendor/images/handle-right.png new file mode 100644 index 00000000..6cda2aed Binary files /dev/null and b/code/html/vendor/images/handle-right.png differ diff --git a/code/html/vendor/images/label-off.png b/code/html/vendor/images/label-off.png new file mode 100644 index 00000000..e135de1d Binary files /dev/null and b/code/html/vendor/images/label-off.png differ diff --git a/code/html/vendor/images/label-on.png b/code/html/vendor/images/label-on.png new file mode 100644 index 00000000..47e4c2ee Binary files /dev/null and b/code/html/vendor/images/label-on.png differ diff --git a/code/html/jquery-3.2.1.min.js b/code/html/vendor/jquery-3.2.1.min.js similarity index 100% rename from code/html/jquery-3.2.1.min.js rename to code/html/vendor/jquery-3.2.1.min.js diff --git a/code/html/jquery.wheelcolorpicker-3.0.3.css b/code/html/vendor/jquery.wheelcolorpicker-3.0.3.css similarity index 100% rename from code/html/jquery.wheelcolorpicker-3.0.3.css rename to code/html/vendor/jquery.wheelcolorpicker-3.0.3.css diff --git a/code/html/jquery.wheelcolorpicker-3.0.3.min.js b/code/html/vendor/jquery.wheelcolorpicker-3.0.3.min.js similarity index 100% rename from code/html/jquery.wheelcolorpicker-3.0.3.min.js rename to code/html/vendor/jquery.wheelcolorpicker-3.0.3.min.js diff --git a/code/html/vendor/pure-1.0.0.min.css b/code/html/vendor/pure-1.0.0.min.css new file mode 100644 index 00000000..b51d749e --- /dev/null +++ b/code/html/vendor/pure-1.0.0.min.css @@ -0,0 +1,11 @@ +/*! +Pure v1.0.0 +Copyright 2013 Yahoo! +Licensed under the BSD License. +https://github.com/pure-css/pure/blob/master/LICENSE.md +*/ +/*! +normalize.css v^3.0 | MIT License | git.io/normalize +Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-flow:row wrap;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-align-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){table .pure-g{display:block}}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class*=pure-u]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}.pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-.43em}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:none transparent;background-color:#e6e6e6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;opacity:.4;cursor:not-allowed;-webkit-box-shadow:none;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{margin:0;border-radius:0;border-right:1px solid #111;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=color]:focus,.pure-form input[type=date]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=email]:focus,.pure-form input[type=month]:focus,.pure-form input[type=number]:focus,.pure-form input[type=password]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=text]:focus,.pure-form input[type=time]:focus,.pure-form input[type=url]:focus,.pure-form input[type=week]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129fea}.pure-form input:not([type]):focus{outline:0;border-color:#129fea}.pure-form input[type=checkbox]:focus,.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus{outline:thin solid #129fea;outline:1px auto #129fea}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=color][disabled],.pure-form input[type=date][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=email][disabled],.pure-form input[type=month][disabled],.pure-form input[type=number][disabled],.pure-form input[type=password][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=text][disabled],.pure-form input[type=time][disabled],.pure-form input[type=url][disabled],.pure-form input[type=week][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=color],.pure-form-stacked input[type=date],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=email],.pure-form-stacked input[type=file],.pure-form-stacked input[type=month],.pure-form-stacked input[type=number],.pure-form-stacked input[type=password],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=text],.pure-form-stacked input[type=time],.pure-form-stacked input[type=url],.pure-form-stacked input[type=week],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned .pure-help-inline,.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline{display:inline-block;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-3-4{width:75%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=color],.pure-group input[type=date],.pure-group input[type=datetime-local],.pure-group input[type=datetime],.pure-group input[type=email],.pure-group input[type=month],.pure-group input[type=number],.pure-group input[type=password],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=text],.pure-group input[type=time],.pure-group input[type=url],.pure-group input[type=week]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0 0}.pure-form .pure-help-inline,.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;zoom:1;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar{display:none}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-disabled,.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected .pure-menu-link,.pure-menu-selected .pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} \ No newline at end of file diff --git a/code/html/vendor/pure-grids-responsive-1.0.0.min.css b/code/html/vendor/pure-grids-responsive-1.0.0.min.css new file mode 100644 index 00000000..df66ab56 --- /dev/null +++ b/code/html/vendor/pure-grids-responsive-1.0.0.min.css @@ -0,0 +1,7 @@ +/*! +Pure v1.0.0 +Copyright 2013 Yahoo! +Licensed under the BSD License. +https://github.com/pure-css/pure/blob/master/LICENSE.md +*/ +@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-12,.pure-u-lg-1-2,.pure-u-lg-1-24,.pure-u-lg-1-3,.pure-u-lg-1-4,.pure-u-lg-1-5,.pure-u-lg-1-6,.pure-u-lg-1-8,.pure-u-lg-10-24,.pure-u-lg-11-12,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-2-24,.pure-u-lg-2-3,.pure-u-lg-2-5,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24,.pure-u-lg-3-24,.pure-u-lg-3-4,.pure-u-lg-3-5,.pure-u-lg-3-8,.pure-u-lg-4-24,.pure-u-lg-4-5,.pure-u-lg-5-12,.pure-u-lg-5-24,.pure-u-lg-5-5,.pure-u-lg-5-6,.pure-u-lg-5-8,.pure-u-lg-6-24,.pure-u-lg-7-12,.pure-u-lg-7-24,.pure-u-lg-7-8,.pure-u-lg-8-24,.pure-u-lg-9-24{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%}.pure-u-lg-1-5{width:20%}.pure-u-lg-5-24{width:20.8333%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%}.pure-u-lg-7-24{width:29.1667%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%}.pure-u-lg-2-5{width:40%}.pure-u-lg-10-24,.pure-u-lg-5-12{width:41.6667%}.pure-u-lg-11-24{width:45.8333%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%}.pure-u-lg-13-24{width:54.1667%}.pure-u-lg-14-24,.pure-u-lg-7-12{width:58.3333%}.pure-u-lg-3-5{width:60%}.pure-u-lg-15-24,.pure-u-lg-5-8{width:62.5%}.pure-u-lg-16-24,.pure-u-lg-2-3{width:66.6667%}.pure-u-lg-17-24{width:70.8333%}.pure-u-lg-18-24,.pure-u-lg-3-4{width:75%}.pure-u-lg-19-24{width:79.1667%}.pure-u-lg-4-5{width:80%}.pure-u-lg-20-24,.pure-u-lg-5-6{width:83.3333%}.pure-u-lg-21-24,.pure-u-lg-7-8{width:87.5%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%}.pure-u-lg-23-24{width:95.8333%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-24-24,.pure-u-lg-5-5{width:100%}} \ No newline at end of file diff --git a/code/html/side-menu.css b/code/html/vendor/side-menu.css similarity index 94% rename from code/html/side-menu.css rename to code/html/vendor/side-menu.css index 7abd61cd..2c37104c 100644 --- a/code/html/side-menu.css +++ b/code/html/vendor/side-menu.css @@ -29,12 +29,12 @@ This is the parent `
` that contains the menu and the content area. padding-left: 0; } #layout.active #menu { - left: 150px; - width: 150px; + left: 160px; + width: 160px; } #layout.active .menu-link { - left: 150px; + left: 160px; } /* The content `
` is where all your content goes. @@ -80,8 +80,8 @@ appears on the left side of the page. */ #menu { - margin-left: -150px; /* "#menu" width */ - width: 150px; + margin-left: -160px; /* "#menu" width */ + width: 160px; position: fixed; top: 0; left: 0; @@ -216,21 +216,21 @@ Hides the menu at `48em`, but modify this based on your app's needs. } #layout { - padding-left: 150px; /* left col width "#menu" */ + padding-left: 160px; /* left col width "#menu" */ left: 0; } #menu { - left: 150px; + left: 160px; } .menu-link { position: fixed; - left: 150px; + left: 160px; display: none; } #layout.active .menu-link { - left: 150px; + left: 160px; } } @@ -243,6 +243,6 @@ Hides the menu at `48em`, but modify this based on your app's needs. */ #layout.active { position: relative; - left: 150px; + left: 160px; } } diff --git a/code/memanalyzer.py b/code/memanalyzer.py new file mode 100644 index 00000000..c2f236b1 --- /dev/null +++ b/code/memanalyzer.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +# coding=utf-8 +# ------------------------------------------------------------------------------- +# ESPurna module memory analyser +# xose.perez@gmail.com +# +# Based on: +# https://github.com/letscontrolit/ESPEasy/blob/mega/memanalyzer.py +# by psy0rz +# https://raw.githubusercontent.com/SmingHub/Sming/develop/tools/memanalyzer.py +# by Slavey Karadzhov +# https://github.com/Sermus/ESP8266_memory_analyzer +# by Andrey Filimonov +# +# ------------------------------------------------------------------------------- +from __future__ import print_function + +import argparse +import os +import re +import shlex +import sys +from collections import OrderedDict +from sortedcontainers import SortedDict +import subprocess + +if (sys.version_info > (3, 0)): + from subprocess import getstatusoutput as getstatusoutput +else: + from commands import getstatusoutput as getstatusoutput + +# ------------------------------------------------------------------------------- + +TOTAL_IRAM = 32786 +TOTAL_DRAM = 81920 +env = "esp8266-4m-ota" +objdump_binary = "xtensa-lx106-elf-objdump" +sections = OrderedDict([ + ("data", "Initialized Data (RAM)"), + ("rodata", "ReadOnly Data (RAM)"), + ("bss", "Uninitialized Data (RAM)"), + ("text", "Cached Code (IRAM)"), + ("irom0_text", "Uncached Code (SPI)") +]) +description = "ESPurna Memory Analyzer v0.1" + + +# ------------------------------------------------------------------------------- + +def file_size(file): + try: + return os.stat(file).st_size + except OSError: + return 0 + + +def analyse_memory(elf_file): + command = "%s -t '%s' " % (objdump_binary, elf_file) + response = subprocess.check_output(shlex.split(command)) + if isinstance(response, bytes): + response = response.decode('utf-8') + lines = response.split('\n') + + # print("{0: >10}|{1: >30}|{2: >12}|{3: >12}|{4: >8}".format("Section", "Description", "Start (hex)", "End (hex)", "Used space")); + # print("------------------------------------------------------------------------------"); + ret = {} + + for (id_, _) in list(sections.items()): + section_start_token = " _%s_start" % id_ + section_end_token = " _%s_end" % id_ + section_start = -1 + section_end = -1 + for line in lines: + if section_start_token in line: + data = line.split(' ') + section_start = int(data[0], 16) + + if section_end_token in line: + data = line.split(' ') + section_end = int(data[0], 16) + + if section_start != -1 and section_end != -1: + break + + section_length = section_end - section_start + # if i < 3: + # usedRAM += section_length + # if i == 3: + # usedIRAM = TOTAL_IRAM - section_length; + + ret[id_] = section_length + # print("{0: >10}|{1: >30}|{2:12X}|{3:12X}|{4:8}".format(id_, descr, section_start, section_end, section_length)) + # i += 1 + + # print("Total Used RAM : %d" % usedRAM) + # print("Free RAM : %d" % (TOTAL_DRAM - usedRAM)) + # print("Free IRam : %d" % usedIRAM) + return ret + + +def run(env_, modules_): + flags = "" + for item in modules_.items(): + 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_) + subprocess.check_call(command, shell=True) + + +def modules_get(): + modules_ = SortedDict() + for line in open("espurna/config/arduino.h"): + m = re.search(r'(\w*)_SUPPORT', line) + if m: + modules_[m.group(1)] = 0 + del modules_['LLMNR'] + del modules_['NETBIOS'] + return modules_ + +try: + + # Parse command line options + parser = argparse.ArgumentParser(description=description) + parser.add_argument("modules", nargs='*', help="Modules to test (use ALL to test them all)") + parser.add_argument("-c", "--core", help="use core as base configuration instead of default", default=0, action='count') + parser.add_argument("-l", "--list", help="list available modules", default=0, action='count') + args = parser.parse_args() + + # Hello + print() + print(description) + print() + + # Check xtensa-lx106-elf-objdump is in the path + status, result = getstatusoutput(objdump_binary) + if status != 2 and status != 512: + print("xtensa-lx106-elf-objdump not found, please check it is in your PATH") + sys.exit(1) + + # Load list of all modules + available_modules = modules_get() + if args.list > 0: + print("List of available modules:\n") + for key, value in available_modules.items(): + print("* " + key) + print() + sys.exit(0) + + # Which modules to test? + test_modules = [] + if len(args.modules) > 0: + if "ALL" in args.modules: + test_modules = available_modules.keys() + else: + test_modules = args.modules + + # Check test modules exist + for module in test_modules: + if module not in available_modules: + print("Module %s not found" % module) + sys.exit(2) + + # Define base configuration + if args.core == 0: + modules = SortedDict() + for m in test_modules: + modules[m] = 0 + else: + modules = available_modules + + # Show init message + if len(test_modules) > 0: + print("Analyzing module(s) %s on top of %s configuration\n" % (", ".join(test_modules), "CORE" if args.core > 0 else "DEFAULT")) + else: + print("Analyzing %s configuration\n" % ("CORE" if args.core > 0 else "DEFAULT")) + + output_format = "{:<20}|{:<11}|{:<11}|{:<11}|{:<11}|{:<11}|{:<12}" + print(output_format.format( + "Module", + "Cache IRAM", + "Init RAM", + "R.O. RAM", + "Uninit RAM", + "Flash ROM", + "Binary size" + )) + + # Build the core without modules to get base memory usage + run(env, modules) + base = analyse_memory(".pioenvs/%s/firmware.elf" % env) + base['size'] = file_size(".pioenvs/%s/firmware.bin" % env) + print(output_format.format( + "CORE" if args.core == 1 else "DEFAULT", + base['text'], + base['data'], + base['rodata'], + base['bss'], + base['irom0_text'], + base['size'], + )) + + # Test each module + results = {} + for module in test_modules: + + modules[module] = 1 + run(env, modules) + results[module] = analyse_memory(".pioenvs/%s/firmware.elf" % env) + results[module]['size'] = file_size(".pioenvs/%s/firmware.bin" % env) + modules[module] = 0 + + print(output_format.format( + module, + results[module]['text'] - base['text'], + results[module]['data'] - base['data'], + results[module]['rodata'] - base['rodata'], + results[module]['bss'] - base['bss'], + results[module]['irom0_text'] - base['irom0_text'], + results[module]['size'] - base['size'], + )) + + # Test all modules + if len(test_modules) > 0: + + for module in test_modules: + modules[module] = 1 + run(env, modules) + total = analyse_memory(".pioenvs/%s/firmware.elf" % env) + total['size'] = file_size(".pioenvs/%s/firmware.bin" % env) + + if len(test_modules) > 1: + print(output_format.format( + "ALL MODULES", + total['text'] - base['text'], + total['data'] - base['data'], + total['rodata'] - base['rodata'], + total['bss'] - base['bss'], + total['irom0_text'] - base['irom0_text'], + total['size'] - base['size'], + )) + + print(output_format.format( + "TOTAL", + total['text'], + total['data'], + total['rodata'], + total['bss'], + total['irom0_text'], + total['size'], + )) + +except: + raise + +subprocess.check_call("export ESPURNA_BOARD=\"\"; export ESPURNA_FLAGS=\"\"", shell=True) + +print("\n") diff --git a/code/ota.py b/code/ota.py new file mode 100755 index 00000000..2a268acf --- /dev/null +++ b/code/ota.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python +# coding=utf-8 +# ------------------------------------------------------------------------------- +# ESPurna OTA manager +# xose.perez@gmail.com +# +# Requires PlatformIO Core +# ------------------------------------------------------------------------------- +from __future__ import print_function + +import argparse +import re +import socket +import subprocess +import sys +import time + +from zeroconf import ServiceBrowser, ServiceStateChange, Zeroconf + +try: + # noinspection PyUnresolvedReferences + input = raw_input # Python2 *!! redefining build-in input. +except NameError: + pass # Python3 + +# ------------------------------------------------------------------------------- + +DISCOVER_TIMEOUT = 2 + +description = "ESPurna OTA Manager v0.2" +devices = [] +discover_last = 0 + +# ------------------------------------------------------------------------------- + +def on_service_state_change(zeroconf, service_type, name, state_change): + """ + Callback that adds discovered devices to "devices" list + """ + + if state_change is ServiceStateChange.Added: + discover_last = time.time() + info = zeroconf.get_service_info(service_type, name) + if info: + + hostname = info.server.split(".")[0] + device = { + 'hostname': hostname.upper(), + 'ip': socket.inet_ntoa(info.address), + 'mac': '', + 'app_name': '', + 'app_version': '', + 'target_board': '', + 'mem_size': '', + 'sdk_size': '', + 'free_space': '', + } + + for key, item in info.properties.items(): + device[key.decode('UTF-8')] = item.decode('UTF-8'); + + devices.append(device) + + +def list_devices(): + """ + Shows the list of discovered devices + """ + output_format="{:>3} {:<14} {:<15} {:<17} {:<12} {:<8} {:<25} {:<8} {:<8} {:<10}" + print(output_format.format( + "#", + "HOSTNAME", + "IP", + "MAC", + "APP", + "VERSION", + "DEVICE", + "MEM_SIZE", + "SDK_SIZE", + "FREE_SPACE" + )) + print("-" * 139) + + index = 0 + for device in devices: + index = index + 1 + print(output_format.format( + index, + device.get('hostname', ''), + device.get('ip', ''), + device.get('mac', ''), + device.get('app_name', ''), + device.get('app_version', ''), + device.get('target_board', ''), + device.get('mem_size', ''), + device.get('sdk_size', ''), + device.get('free_space', ''), + )) + + print() + + +def get_boards(): + """ + Grabs board types fro hardware.h file + """ + boards = [] + for line in open("espurna/config/hardware.h"): + m = re.search(r'defined\((\w*)\)', line) + if m: + boards.append(m.group(1)) + return sorted(boards) + +def get_empty_board(): + """ + Returns the empty structure of a board to flash + """ + board = {'board': '', 'ip': '', 'size': 0, 'auth': '', 'flags': ''} + return board + +def get_board_by_index(index): + """ + Returns the required data to flash a given board + """ + board = {} + if 1 <= index and index <= len(devices): + device = devices[index - 1] + board['hostname'] = device.get('hostname') + board['board'] = device.get('target_board', '') + board['ip'] = device.get('ip', '') + board['size'] = int(device.get('mem_size', 0) if device.get('mem_size', 0) == device.get('sdk_size', 0) else 0) / 1024 + return board + +def get_board_by_hostname(hostname): + """ + Returns the required data to flash a given board + """ + hostname = hostname.lower() + for device in devices: + if device.get('hostname', '').lower() == hostname: + board = {} + board['hostname'] = device.get('hostname') + board['board'] = device.get('target_board') + if not board['board']: + return None + board['ip'] = device.get('ip') + if not board['ip']: + return None + board['size'] = int(device.get('sdk_size', 0)) / 1024 + if board['size'] == 0: + return None + return board + return None + +def input_board(): + """ + Grabs info from the user about what device to flash + """ + + # Choose the board + try: + index = int(input("Choose the board you want to flash (empty if none of these): ")) + except ValueError: + index = 0 + if index < 0 or len(devices) < index: + print("Board number must be between 1 and %s\n" % str(len(devices))) + return None + + board = get_board_by_index(index); + + # Choose board type if none before + if len(board.get('board', '')) == 0: + + print() + count = 1 + boards = get_boards() + for name in boards: + print("%3d\t%s" % (count, name)) + count = count + 1 + print() + try: + index = int(input("Choose the board type you want to flash: ")) + except ValueError: + index = 0 + if index < 1 or len(boards) < index: + print("Board number must be between 1 and %s\n" % str(len(boards))) + return None + board['board'] = boards[index - 1] + + # Choose board size of none before + if board.get('size', 0) == 0: + try: + board['size'] = int(input("Board memory size (1 for 1M, 4 for 4M): ")) + except ValueError: + print("Wrong memory size") + return None + + # Choose IP of none before + if len(board.get('ip', '')) == 0: + board['ip'] = input("IP of the device to flash (empty for 192.168.4.1): ") or "192.168.4.1" + + return board + + +def run(device, env): + print("Building and flashing image over-the-air...") + command = "export ESPURNA_IP=\"%s\"; export ESPURNA_BOARD=\"%s\"; export ESPURNA_AUTH=\"%s\"; export ESPURNA_FLAGS=\"%s\"; platformio run --silent --environment %s -t upload" + command = command % (device['ip'], device['board'], device['auth'], device['flags'], env) + subprocess.check_call(command, shell=True) + + +# ------------------------------------------------------------------------------- + +if __name__ == '__main__': + + # Parse command line options + parser = argparse.ArgumentParser(description=description) + parser.add_argument("-c", "--core", help="flash ESPurna core", default=0, action='count') + parser.add_argument("-f", "--flash", help="flash device", default=0, action='count') + parser.add_argument("-o", "--flags", help="extra flags", default='') + parser.add_argument("-p", "--password", help="auth password", default='') + parser.add_argument("-s", "--sort", help="sort devices list by field", default='hostname') + parser.add_argument("-y", "--yes", help="do not ask for confirmation", default=0, action='count') + parser.add_argument("hostnames", nargs='*', help="Hostnames to update") + args = parser.parse_args() + + print() + print(description) + print() + + # Look for sevices + zeroconf = Zeroconf() + browser = ServiceBrowser(zeroconf, "_arduino._tcp.local.", handlers=[on_service_state_change]) + discover_last = time.time() + while time.time() < discover_last + DISCOVER_TIMEOUT: + None + #zeroconf.close() + + if len(devices) == 0: + print("Nothing found!\n") + sys.exit(0) + + # Sort list + field = args.sort.lower() + if field not in devices[0]: + print("Unknown field '%s'\n" % field) + sys.exit(1) + devices = sorted(devices, key=lambda device: device.get(field, '')) + + # List devices + list_devices() + + # Flash device + if args.flash > 0: + + # Board(s) to flash + queue = [] + + # Check if hostnames + for hostname in args.hostnames: + board = get_board_by_hostname(hostname) + if board: + board['auth'] = args.password + board['flags'] = args.flags + queue.append(board) + + # If no boards ask the user + if len(queue) == 0: + board = input_board() + if board: + board['auth'] = args.password or input("Authorization key of the device to flash: ") + board['flags'] = args.flags or input("Extra flags for the build: ") + queue.append(board) + + # If still no boards quit + if len(queue) == 0: + sys.exit(0) + + # Flash eash board + for board in queue: + + # Flash core version? + if args.core > 0: + board['flags'] = "-DESPURNA_CORE " + board['flags'] + + env = "esp8266-%sm-ota" % board['size'] + + # Summary + print() + print("HOST = %s" % board.get('hostname', board['ip'])) + print("IP = %s" % board['ip']) + print("BOARD = %s" % board['board']) + print("AUTH = %s" % board['auth']) + print("FLAGS = %s" % board['flags']) + print("ENV = %s" % env) + + response = True + if args.yes == 0: + response = (input("\nAre these values right [y/N]: ") == "y") + if response: + print() + run(board, env) diff --git a/code/ota_flash.sh b/code/ota_flash.sh deleted file mode 100755 index aef002cf..00000000 --- a/code/ota_flash.sh +++ /dev/null @@ -1,225 +0,0 @@ -#!/bin/bash - -ip= -board= -size= -auth= -flags= - -export boards=() -ips="" - -exists() { - command -v "$1" >/dev/null 2>&1 -} - -echo_pad() { - string=$1 - pad=$2 - printf '%s' "$string" - printf '%*s' $(( $pad - ${#string} )) -} - -useAvahi() { - - echo_pad "#" 4 - echo_pad "HOSTNAME" 25 - echo_pad "IP" 25 - echo_pad "APP" 15 - echo_pad "VERSION" 15 - echo_pad "DEVICE" 30 - echo_pad "MEM_SIZE" 10 - echo_pad "SDK_SIZE" 10 - echo - - printf -v line '%*s\n' 134 - echo ${line// /-} - - counter=0 - - ip_file="/tmp/espurna.flash.ips" - board_file="/tmp/espurna.flash.boards" - count_file="/tmp/espurna.flash.count" - size_file="/tmp/espurna.flash.size" - echo -n "" > $ip_file - echo -n "" > $board_file - echo -n "" > $size_file - echo -n "$counter" > $count_file - - avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | sort -t ';' -k 3 | while read line; do - - (( counter++ )) - echo "$counter" > $count_file - - hostname=`echo $line | cut -d ';' -f4` - ip=`echo $line | cut -d ';' -f8` - txt=`echo $line | cut -d ';' -f10` - app_name=`echo $txt | sed -n "s/.*app_name=\([^\"]*\).*/\1/p"` - app_version=`echo $txt | sed -n "s/.*app_version=\([^\"]*\).*/\1/p"` - board=`echo $txt | sed -n "s/.*target_board=\([^\"]*\).*/\1/p"` - mem_size=`echo $txt | sed -n "s/.*mem_size=\([^\"]*\).*/\1/p"` - sdk_size=`echo $txt | sed -n "s/.*sdk_size=\([^\"]*\).*/\1/p"` - - echo_pad "$counter" 4 - echo_pad "$hostname" 25 - echo_pad "http://$ip" 25 - echo_pad "$app_name" 15 - echo_pad "$app_version" 15 - echo_pad "$board" 30 - echo_pad "$mem_size" 10 - echo_pad "$sdk_size" 10 - echo - - echo -n "$ip;" >> $ip_file - echo -n "$board;" >> $board_file - if [ "$mem_size" == "$sdk_size" ]; then - mem_size=`echo $mem_size | head -c 1` - echo -n "$mem_size;" >> $size_file - else - echo -n ";" >> $size_file - fi - - done - - echo - read -p "Choose the board you want to flash (empty if none of these): " num - - # None of these - if [ "$num" == "" ]; then - return - fi - - # Check boundaries - counter=`cat $count_file` - if [ $num -lt 1 ] || [ $num -gt $counter ]; then - echo "Board number must be between 1 and $counter" - exit 1 - fi - - # Fill the fields - ip=`cat $ip_file | cut -d ';' -f$num` - board=`cat $board_file | cut -d ';' -f$num` - size=`cat $size_file | cut -d ';' -f$num` - -} - -getBoard() { - - boards=(`cat espurna/config/hardware.h | grep "defined" | sed "s/.*(\(.*\)).*/\1/" | sort`) - - echo_pad "#" 4 - echo_pad "DEVICE" 30 - echo - - printf -v line '%*s\n' 34 - echo ${line// /-} - - counter=0 - for board in "${boards[@]}"; do - (( counter++ )) - echo_pad "$counter" 4 - echo_pad "$board" 30 - echo - done - - echo - read -p "Choose the board you want to flash (empty if none of these): " num - - # None of these - if [ "$num" == "" ]; then - return - fi - - # Check boundaries - counter=${#boards[*]} - if [ $num -lt 1 ] || [ $num -gt $counter ]; then - echo "Board code must be between 1 and $counter" - exit 1 - fi - - # Fill the fields - (( num -- )) - board=${boards[$num]} - -} - -# ------------------------------------------------------------------------------ - -# Welcome -echo -echo "--------------------------------------------------------------" -echo "ESPURNA FIRMWARE OTA FLASHER" - -# Get current version -version=`cat espurna/config/version.h | grep APP_VERSION | awk '{print $3}' | sed 's/"//g'` -echo "Building for version $version" - -echo "--------------------------------------------------------------" -echo - -if exists avahi-browse; then - useAvahi -fi - -if [ "$board" == "" ]; then - getBoard -fi - -if [ "$board" == "" ]; then - read -p "Board type of the device to flash: " -e -i "NODEMCU_LOLIN" board -fi - -if [ "$board" == "" ]; then - echo "You must define the board type" - exit 2 -fi - -if [ "$size" == "" ]; then - read -p "Board memory size (1 for 1M, 4 for 4M): " -e size -fi - -if [ "$size" == "" ]; then - echo "You must define the board memory size" - exit 2 -fi - -if [ "$ip" == "" ]; then - read -p "IP of the device to flash: " -e -i 192.168.4.1 ip -fi - -if [ "$ip" == "" ]; then - echo "You must define the IP of the device" - exit 2 -fi - -if [ "$auth" == "" ]; then - read -p "Authorization key of the device to flash: " auth -fi - -if [ "$flags" == "" ]; then - read -p "Extra flags for the build: " -e -i "" flags -fi - -env="esp8266-${size}m-ota" - -echo -echo "ESPURNA_IP = $ip" -echo "ESPURNA_BOARD = $board" -echo "ESPURNA_AUTH = $auth" -echo "ESPURNA_FLAGS = $flags" -echo "ESPURNA_ENV = $env" - -echo -echo -n "Are these values corrent [y/N]: " -read response - -if [ "$response" != "y" ]; then - exit -fi - -export ESPURNA_IP=$ip -export ESPURNA_BOARD=$board -export ESPURNA_AUTH=$auth -export ESPURNA_FLAGS=$flags - -pio run -e $env -t upload diff --git a/code/ota_list.sh b/code/ota_list.sh deleted file mode 100755 index 6a988db9..00000000 --- a/code/ota_list.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -exists() { - command -v "$1" >/dev/null 2>&1 -} - -echo_pad() { - string=$1 - pad=$2 - printf '%s' "$string" - printf '%*s' $(( $pad - ${#string} )) -} - -useAvahi() { - - echo_pad "#" 4 - echo_pad "HOSTNAME" 25 - echo_pad "IP" 25 - echo_pad "APP" 15 - echo_pad "VERSION" 15 - echo_pad "DEVICE" 30 - echo_pad "MEM_SIZE" 10 - echo_pad "SDK_SIZE" 10 - echo - - printf -v line '%*s\n' 134 - echo ${line// /-} - - counter=0 - - avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | sort -t ';' -k 3 | while read line; do - - (( counter++ )) - - hostname=`echo $line | cut -d ';' -f4` - ip=`echo $line | cut -d ';' -f8` - txt=`echo $line | cut -d ';' -f10` - app_name=`echo $txt | sed -n "s/.*app_name=\([^\"]*\).*/\1/p"` - app_version=`echo $txt | sed -n "s/.*app_version=\([^\"]*\).*/\1/p"` - board=`echo $txt | sed -n "s/.*target_board=\([^\"]*\).*/\1/p"` - mem_size=`echo $txt | sed -n "s/.*mem_size=\([^\"]*\).*/\1/p"` - sdk_size=`echo $txt | sed -n "s/.*sdk_size=\([^\"]*\).*/\1/p"` - - echo_pad "$counter" 4 - echo_pad "$hostname" 25 - echo_pad "http://$ip" 25 - echo_pad "$app_name" 15 - echo_pad "$app_version" 15 - echo_pad "$board" 30 - echo_pad "$mem_size" 10 - echo_pad "$sdk_size" 10 - echo - - done - - echo - -} - -# ------------------------------------------------------------------------------ - -# Welcome -echo -echo "--------------------------------------------------------------" -echo "OTA-UPDATABLE DEVICES" -echo "--------------------------------------------------------------" -echo - -if exists avahi-browse; then - useAvahi -else - echo "Avahi not installed" - exit 1 -fi diff --git a/code/package-lock.json b/code/package-lock.json new file mode 100644 index 00000000..2327264c --- /dev/null +++ b/code/package-lock.json @@ -0,0 +1,4314 @@ +{ + "name": "esp8266-filesystem-builder", + "version": "0.2.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "fast-deep-equal": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "fast-json-stable-stringify": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "json-schema-traverse": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz" + } + }, + "align-text": { + "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "longest": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + }, + "dependencies": { + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "amdefine": { + "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-colors": { + "version": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha1-Y3S03V1HGP884npnGjscrQdxMqk=", + "dev": true, + "requires": { + "ansi-wrap": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz" + } + }, + "ansi-gray": { + "version": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz" + } + }, + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "ansi-wrap": { + "version": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "any-promise": { + "version": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "dev": true + }, + "arr-union": { + "version": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-differ": { + "version": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, + "array-union": { + "version": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" + } + }, + "array-uniq": { + "version": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "asynckit": { + "version": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", + "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=", + "dev": true + }, + "aws-sign2": { + "version": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "balanced-match": { + "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + } + } + }, + "bcrypt-pbkdf": { + "version": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" + } + }, + "beeper": { + "version": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "dev": true + }, + "binaryextensions": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz", + "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==", + "dev": true + }, + "boolbase": { + "version": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz" + } + }, + "brace-expansion": { + "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "dev": true, + "requires": { + "balanced-match": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + } + }, + "braces": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", + "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", + "dev": true, + "requires": { + "arr-flatten": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "array-unique": "0.3.2", + "define-property": "1.0.0", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "kind-of": "6.0.2", + "repeat-element": "1.1.2", + "snapdragon": "0.8.1", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "buffers": { + "version": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true + }, + "bufferstreams": { + "version": "https://registry.npmjs.org/bufferstreams/-/bufferstreams-1.1.3.tgz", + "integrity": "sha1-qFFawCT6kOj6fVjBGxPeofKKvnI=", + "dev": true, + "requires": { + "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz" + }, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", + "integrity": "sha1-yUbD9H+n2Oq8C2FQ9KEvaaRXQHE=", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + } + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true, + "requires": { + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" + } + } + } + }, + "bulk-require": { + "version": "https://registry.npmjs.org/bulk-require/-/bulk-require-1.0.1.tgz", + "integrity": "sha1-yz0DnmmBOaRE/FdLJh1rOyz0TIk=", + "dev": true, + "requires": { + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz" + } + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" + } + }, + "camel-case": { + "version": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" + } + }, + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "caseless": { + "version": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "lazy-cache": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" + }, + "dependencies": { + "lazy-cache": { + "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + } + } + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + } + }, + "change-case": { + "version": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha1-/Uh0bM4C8D8KZyV30dOo3C7OsDc=", + "dev": true, + "requires": { + "camel-case": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "constant-case": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "dot-case": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "header-case": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "is-lower-case": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "is-upper-case": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "lower-case-first": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "param-case": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "pascal-case": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "path-case": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "sentence-case": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "snake-case": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "swap-case": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "title-case": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "upper-case-first": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz" + } + }, + "cheerio": { + "version": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "dev": true, + "requires": { + "css-select": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "dom-serializer": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "entities": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "htmlparser2": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "lodash.assignin": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "lodash.bind": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "lodash.defaults": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "lodash.filter": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "lodash.flatten": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "lodash.foreach": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "lodash.map": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "lodash.merge": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "lodash.pick": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "lodash.reduce": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "lodash.reject": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "lodash.some": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz" + } + }, + "clap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "define-property": "0.2.5", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "static-extend": "0.1.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "cliui": { + "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "right-align": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" + } + }, + "clone": { + "version": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", + "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=", + "dev": true + }, + "clone-buffer": { + "version": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-stats": { + "version": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "cloneable-readable": { + "version": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz", + "integrity": "sha1-pikNQT8hemEjL5XkWP84QYz7ARc=", + "dev": true, + "requires": { + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz" + }, + "dependencies": { + "process-nextick-args": { + "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + } + } + }, + "co": { + "version": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "1.5.1" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "1.0.0", + "object-visit": "1.0.1" + } + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-support": { + "version": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + } + }, + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + } + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "constant-case": { + "version": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=", + "dev": true, + "requires": { + "snake-case": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "crass": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/crass/-/crass-0.12.3.tgz", + "integrity": "sha512-0gOYgXVAr6KF7xNUv/+QmTrVsMowpuYu9y1SWzMHFrERzxTygqpeBTXI9CMg1NI1AwQ96ZrkaGHVT9eTC66+Tw==", + "dev": true, + "requires": { + "color-convert": "1.9.1", + "strong-data-uri": "1.0.5", + "svgo": "0.7.2" + } + }, + "cryptiles": { + "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz" + }, + "dependencies": { + "boom": { + "version": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", + "dev": true, + "requires": { + "hoek": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz" + } + } + } + }, + "css-select": { + "version": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "css-what": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "domutils": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "nth-check": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz" + }, + "dependencies": { + "domutils": { + "version": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "domelementtype": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz" + } + } + } + }, + "css-what": { + "version": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "csslint": { + "version": "https://registry.npmjs.org/csslint/-/csslint-1.0.5.tgz", + "integrity": "sha1-Gcw+2jIhYP0/cjKvHLKjYOiYouk=", + "dev": true, + "requires": { + "clone": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "parserlib": "https://registry.npmjs.org/parserlib/-/parserlib-1.1.1.tgz" + }, + "dependencies": { + "clone": { + "version": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + } + } + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "1.2.3", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + } + }, + "csswring": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/csswring/-/csswring-6.0.3.tgz", + "integrity": "sha512-Cz2/8nVqI6li/t4hfZbPTQDF7FkE4qP534j1xbBnLxA1cYl51ZRSg0PTDVWzbzlSsR+tfV2Iv/w+0cTmfKS7JA==", + "dev": true, + "requires": { + "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "onecolor": "3.0.5", + "postcss": "6.0.21" + } + }, + "dashdash": { + "version": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + } + }, + "dateformat": { + "version": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "dev": true + }, + "deap": { + "version": "https://registry.npmjs.org/deap/-/deap-1.0.0.tgz", + "integrity": "sha1-sUi/gkMKJ2mbdIOgPra2dYW/yIg=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + } + }, + "del": { + "version": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "is-path-cwd": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "is-path-in-cwd": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz" + } + }, + "delayed-stream": { + "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "deprecated": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", + "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "dom-serializer": { + "version": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "entities": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz" + }, + "dependencies": { + "domelementtype": { + "version": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "domelementtype": { + "version": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", + "dev": true, + "requires": { + "domelementtype": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz" + } + }, + "domutils": { + "version": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", + "dev": true, + "requires": { + "dom-serializer": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "domelementtype": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz" + } + }, + "dot-case": { + "version": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz" + } + }, + "duplexer": { + "version": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "duplexer2": { + "version": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" + } + }, + "ecc-jsbn": { + "version": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" + } + }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, + "end-of-stream": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", + "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "dev": true, + "requires": { + "once": "1.3.3" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + } + } + } + }, + "entities": { + "version": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "event-stream": { + "version": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dev": true, + "requires": { + "duplexer": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "from": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "map-stream": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "pause-stream": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "split": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "stream-combiner": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.1", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1" + } + }, + "extend": { + "version": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extend-shallow": { + "version": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "is-extendable": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz" + }, + "dependencies": { + "is-extendable": { + "version": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "dev": true, + "requires": { + "is-plain-object": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.1", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "extsprintf": { + "version": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fancy-log": { + "version": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", + "dev": true, + "requires": { + "ansi-gray": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "color-support": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "time-stamp": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz" + } + }, + "fast-deep-equal": { + "version": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "dev": true + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "1.0.0", + "is-glob": "3.1.0", + "micromatch": "3.1.9", + "resolve-dir": "1.0.1" + } + }, + "fined": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", + "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "dev": true, + "requires": { + "expand-tilde": "2.0.2", + "is-plain-object": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "object.defaults": "1.1.0", + "object.pick": "1.3.0", + "parse-filepath": "1.0.2" + } + }, + "first-chunk-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", + "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", + "dev": true + }, + "flagged-respawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", + "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "combined-stream": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "0.2.2" + } + }, + "from": { + "version": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "dev": true + }, + "fs.realpath": { + "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "gaze": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", + "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "dev": true, + "requires": { + "globule": "0.1.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + } + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "dev": true, + "requires": { + "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + } + }, + "glob-stream": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", + "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "dev": true, + "requires": { + "glob": "4.5.3", + "glob2base": "0.0.12", + "minimatch": "2.0.10", + "ordered-read-streams": "0.1.0", + "through2": "0.6.5", + "unique-stream": "1.0.0" + }, + "dependencies": { + "glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "dev": true, + "requires": { + "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "minimatch": "2.0.10", + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + } + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + } + } + } + }, + "glob-watcher": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", + "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "dev": true, + "requires": { + "gaze": "0.5.2" + } + }, + "glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "dev": true, + "requires": { + "find-index": "0.1.1" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "1.0.2", + "is-windows": "1.0.2", + "resolve-dir": "1.0.1" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "2.0.2", + "homedir-polyfill": "1.0.1", + "ini": "1.3.5", + "is-windows": "1.0.2", + "which": "1.3.0" + } + }, + "globby": { + "version": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + } + }, + "globule": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", + "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", + "dev": true, + "requires": { + "glob": "3.1.21", + "lodash": "1.0.2", + "minimatch": "0.2.14" + }, + "dependencies": { + "glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "dev": true, + "requires": { + "graceful-fs": "1.2.3", + "inherits": "1.0.2", + "minimatch": "0.2.14" + } + }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "dev": true + }, + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "dev": true + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true, + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + } + } + }, + "glogg": { + "version": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", + "integrity": "sha1-3PdY5EeJzD89MsHzVio2duajSBA=", + "dev": true, + "requires": { + "sparkles": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz" + } + }, + "graceful-fs": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "dev": true, + "requires": { + "natives": "1.1.1" + } + }, + "graceful-readlink": { + "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "gulp": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", + "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", + "dev": true, + "requires": { + "archy": "1.0.0", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "deprecated": "0.0.1", + "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "interpret": "1.1.0", + "liftoff": "2.5.0", + "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "orchestrator": "0.3.8", + "pretty-hrtime": "1.0.3", + "semver": "4.3.6", + "tildify": "1.2.0", + "v8flags": "2.1.1", + "vinyl-fs": "0.3.14" + } + }, + "gulp-base64-favicon": { + "version": "https://registry.npmjs.org/gulp-base64-favicon/-/gulp-base64-favicon-1.0.2.tgz", + "integrity": "sha1-Bz9GpO4p35HpXXon9w7I45gsah0=", + "dev": true + }, + "gulp-crass": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/gulp-crass/-/gulp-crass-0.2.2.tgz", + "integrity": "sha1-RtD38aTamVwiG2ftxJNw95i/eNs=", + "dev": true, + "requires": { + "crass": "0.12.3", + "csswring": "6.0.3", + "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz" + } + }, + "gulp-css-base64": { + "version": "https://registry.npmjs.org/gulp-css-base64/-/gulp-css-base64-1.3.4.tgz", + "integrity": "sha1-r8pF6DQBBF9HLGe3dtGxUU4RSJ8=", + "dev": true, + "requires": { + "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "buffers": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "mime": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "request": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz" + } + }, + "gulp-csslint": { + "version": "https://registry.npmjs.org/gulp-csslint/-/gulp-csslint-1.0.1.tgz", + "integrity": "sha1-ESqQj3rvmO/Ce3vQCAHxOne+y5M=", + "dev": true, + "requires": { + "csslint": "https://registry.npmjs.org/csslint/-/csslint-1.0.5.tgz", + "fancy-log": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "plugin-error": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "rcloader": "https://registry.npmjs.org/rcloader/-/rcloader-0.2.2.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "vinyl": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz" + }, + "dependencies": { + "clone": { + "version": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + }, + "clone-stats": { + "version": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "plugin-error": { + "version": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha1-dwFr2JGdCsN3/c3QMiMolTyleBw=", + "dev": true, + "requires": { + "ansi-colors": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "arr-diff": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "arr-union": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "extend-shallow": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + } + }, + "replace-ext": { + "version": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "vinyl": { + "version": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", + "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", + "dev": true, + "requires": { + "clone": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "clone-buffer": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "clone-stats": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "cloneable-readable": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz", + "remove-trailing-separator": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "replace-ext": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz" + } + } + } + }, + "gulp-gzip": { + "version": "https://registry.npmjs.org/gulp-gzip/-/gulp-gzip-1.4.2.tgz", + "integrity": "sha1-BCKpQBQkhlW1sanuocKr7h1PQzc=", + "dev": true, + "requires": { + "ansi-colors": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "bytes": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "fancy-log": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "plugin-error": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "stream-to-array": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz" + }, + "dependencies": { + "plugin-error": { + "version": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha1-dwFr2JGdCsN3/c3QMiMolTyleBw=", + "dev": true, + "requires": { + "ansi-colors": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "arr-diff": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "arr-union": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "extend-shallow": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + } + } + } + }, + "gulp-htmllint": { + "version": "https://registry.npmjs.org/gulp-htmllint/-/gulp-htmllint-0.0.14.tgz", + "integrity": "sha1-fobrpgVmjfsVstLVAZX+VqdVhaI=", + "dev": true, + "requires": { + "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "htmllint": "https://registry.npmjs.org/htmllint/-/htmllint-0.7.2.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz" + } + }, + "gulp-htmlmin": { + "version": "https://registry.npmjs.org/gulp-htmlmin/-/gulp-htmlmin-2.0.0.tgz", + "integrity": "sha1-EspjV2Q3qt/IWdKt36QcOO/OqGk=", + "dev": true, + "requires": { + "bufferstreams": "https://registry.npmjs.org/bufferstreams/-/bufferstreams-1.1.3.tgz", + "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "html-minifier": "https://registry.npmjs.org/html-minifier/-/html-minifier-2.1.7.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", + "tryit": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz" + }, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", + "integrity": "sha1-yUbD9H+n2Oq8C2FQ9KEvaaRXQHE=", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + } + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true, + "requires": { + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" + } + } + } + }, + "gulp-inline": { + "version": "https://registry.npmjs.org/gulp-inline/-/gulp-inline-0.1.3.tgz", + "integrity": "sha1-iYdqnJNORR12u8tkzAJErA5ZtHw=", + "dev": true, + "requires": { + "cheerio": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "event-stream": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz" + } + }, + "gulp-replace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz", + "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==", + "dev": true, + "requires": { + "istextorbinary": "2.2.1", + "readable-stream": "2.3.6", + "replacestream": "4.0.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "1.0.0", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "string_decoder": "1.1.1", + "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" + } + } + } + }, + "gulp-uglify": { + "version": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-1.5.4.tgz", + "integrity": "sha1-UkeI2HZm0J+dDCH7IXf5ADmmWMk=", + "dev": true, + "requires": { + "deap": "https://registry.npmjs.org/deap/-/deap-1.0.0.tgz", + "fancy-log": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "uglify-js": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", + "uglify-save-license": "https://registry.npmjs.org/uglify-save-license/-/uglify-save-license-0.4.1.tgz", + "vinyl-sourcemaps-apply": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz" + }, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + } + } + } + }, + "gulp-util": { + "version": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "dev": true, + "requires": { + "array-differ": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "array-uniq": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "beeper": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "dateformat": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "fancy-log": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "gulplog": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "has-gulplog": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "lodash._reescape": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "lodash._reevaluate": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "lodash._reinterpolate": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "lodash.template": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "multipipe": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "replace-ext": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "vinyl": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz" + }, + "dependencies": { + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "dev": true + } + } + }, + "gulplog": { + "version": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz" + } + }, + "har-schema": { + "version": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "har-schema": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" + } + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-gulplog": { + "version": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "dev": true, + "requires": { + "sparkles": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "hawk": { + "version": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", + "dev": true, + "requires": { + "boom": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "cryptiles": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "hoek": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "sntp": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz" + } + }, + "he": { + "version": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "header-case": { + "version": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" + } + }, + "hoek": { + "version": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha1-ljRQKqEsRF3Vp8VzS1cruHOKrLs=", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, + "html-minifier": { + "version": "https://registry.npmjs.org/html-minifier/-/html-minifier-2.1.7.tgz", + "integrity": "sha1-kFHW/LvPIU7TB+GtdPQyu5rWVcw=", + "dev": true, + "requires": { + "change-case": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "clean-css": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", + "commander": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "he": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "ncname": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", + "relateurl": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "uglify-js": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz" + }, + "dependencies": { + "clean-css": { + "version": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", + "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", + "dev": true, + "requires": { + "commander": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz" + }, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "dev": true, + "requires": { + "graceful-readlink": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + } + } + } + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" + } + } + } + }, + "htmllint": { + "version": "https://registry.npmjs.org/htmllint/-/htmllint-0.7.2.tgz", + "integrity": "sha1-AuR0FvotvrMLXiw+1mfopUB6jzQ=", + "dev": true, + "requires": { + "bulk-require": "https://registry.npmjs.org/bulk-require/-/bulk-require-1.0.1.tgz", + "htmlparser2": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "promise": "https://registry.npmjs.org/promise/-/promise-8.0.1.tgz" + }, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha1-maktZcAnLevoyWtgV7yPv6O+1RE=", + "dev": true + } + } + }, + "htmlparser2": { + "version": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "domhandler": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", + "domutils": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "entities": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz" + }, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", + "integrity": "sha1-yUbD9H+n2Oq8C2FQ9KEvaaRXQHE=", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + } + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true, + "requires": { + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" + } + } + } + }, + "http-signature": { + "version": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "jsprim": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "sshpk": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz" + } + }, + "inflight": { + "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + } + }, + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "1.0.0", + "is-windows": "1.0.2" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-buffer": { + "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "dev": true + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + }, + "is-lower-case": { + "version": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=", + "dev": true, + "requires": { + "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-odd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", + "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", + "dev": true, + "requires": { + "is-number": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "is-path-cwd": { + "version": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz" + } + }, + "is-path-inside": { + "version": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" + } + }, + "is-plain-object": { + "version": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "dev": true, + "requires": { + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "1.0.0" + } + }, + "is-typedarray": { + "version": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "0.1.2" + } + }, + "is-upper-case": { + "version": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=", + "dev": true, + "requires": { + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istextorbinary": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", + "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", + "dev": true, + "requires": { + "binaryextensions": "2.1.1", + "editions": "1.3.4", + "textextensions": "2.2.0" + } + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "2.7.3" + } + }, + "jsbn": { + "version": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "json-schema": { + "version": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stringify-safe": { + "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "json-schema": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "verror": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "dev": true, + "requires": { + "set-getter": "0.1.0" + } + }, + "liftoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", + "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "dev": true, + "requires": { + "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "findup-sync": "2.0.0", + "fined": "1.1.0", + "flagged-respawn": "1.0.0", + "is-plain-object": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "object.map": "1.0.1", + "rechoir": "0.6.2", + "resolve": "1.5.0" + } + }, + "lodash": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", + "dev": true + }, + "lodash._basecopy": { + "version": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basetostring": { + "version": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "dev": true + }, + "lodash._basevalues": { + "version": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "dev": true + }, + "lodash._getnative": { + "version": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash._reescape": { + "version": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "dev": true + }, + "lodash._reevaluate": { + "version": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "dev": true + }, + "lodash._reinterpolate": { + "version": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash._root": { + "version": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "dev": true + }, + "lodash.assign": { + "version": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.assignin": { + "version": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=", + "dev": true + }, + "lodash.bind": { + "version": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", + "dev": true + }, + "lodash.clonedeep": { + "version": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.defaults": { + "version": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + }, + "lodash.escape": { + "version": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "dev": true, + "requires": { + "lodash._root": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz" + } + }, + "lodash.filter": { + "version": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=", + "dev": true + }, + "lodash.flatten": { + "version": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "lodash.foreach": { + "version": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=", + "dev": true + }, + "lodash.isarguments": { + "version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.isobject": { + "version": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=", + "dev": true + }, + "lodash.keys": { + "version": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "lodash.isarguments": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "lodash.isarray": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + } + }, + "lodash.map": { + "version": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, + "lodash.merge": { + "version": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha1-rcJdnLmbk5HFliTzefu6YNcRHVQ=", + "dev": true + }, + "lodash.pick": { + "version": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", + "dev": true + }, + "lodash.reduce": { + "version": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=", + "dev": true + }, + "lodash.reject": { + "version": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=", + "dev": true + }, + "lodash.restparam": { + "version": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true + }, + "lodash.some": { + "version": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "dev": true + }, + "lodash.template": { + "version": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "lodash._basetostring": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "lodash._basevalues": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "lodash._isiterateecall": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "lodash._reinterpolate": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "lodash.escape": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "lodash.keys": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "lodash.restparam": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "lodash.templatesettings": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz" + } + }, + "lodash.templatesettings": { + "version": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "dev": true, + "requires": { + "lodash._reinterpolate": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "lodash.escape": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz" + } + }, + "longest": { + "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "lower-case": { + "version": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lower-case-first": { + "version": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=", + "dev": true, + "requires": { + "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz" + } + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "make-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.0.tgz", + "integrity": "sha1-V7713IXSOSO6I3ZzJNjo+PPZaUs=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-stream": { + "version": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "1.0.1" + } + }, + "micromatch": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.9.tgz", + "integrity": "sha512-SlIz6sv5UPaAVVFRKodKjCg48EbNoIhgetzfK/Cy0v5U52Z6zB136M8tp0UC9jM53LYbmIRihJszvvqpKkfm9g==", + "dev": true, + "requires": { + "arr-diff": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "array-unique": "0.3.2", + "braces": "2.3.1", + "define-property": "2.0.2", + "extend-shallow": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.1", + "to-regex": "3.0.2" + } + }, + "mime": { + "version": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", + "dev": true + }, + "mime-db": { + "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha1-o0kgUKXLm2NFBUHjnZeI0icng9s=", + "dev": true + }, + "mime-types": { + "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", + "dev": true, + "requires": { + "mime-db": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz" + } + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true, + "requires": { + "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + } + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "1.0.2", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multipipe": { + "version": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "dev": true, + "requires": { + "duplexer2": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz" + } + }, + "nanomatch": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", + "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "dev": true, + "requires": { + "arr-diff": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "fragment-cache": "0.2.1", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.1", + "to-regex": "3.0.2" + } + }, + "natives": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.1.tgz", + "integrity": "sha512-8eRaxn8u/4wN8tGkhlc2cgwwvOLMLUMUn4IYTexMgWd+LyUDfeXVkk2ygQR0hvIHbJQXgHujia3ieUUDwNGkEA==", + "dev": true + }, + "ncname": { + "version": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", + "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=", + "dev": true, + "requires": { + "xml-char-classes": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz" + } + }, + "no-case": { + "version": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", + "dev": true, + "requires": { + "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz" + } + }, + "nth-check": { + "version": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" + } + }, + "oauth-sign": { + "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "requires": { + "array-each": "1.0.1", + "array-slice": "1.1.0", + "for-own": "1.0.0", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "requires": { + "for-own": "1.0.0", + "make-iterator": "1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + } + }, + "once": { + "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + } + }, + "onecolor": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/onecolor/-/onecolor-3.0.5.tgz", + "integrity": "sha1-Nu/zIgE3nv3xGA+0ReUajiQl+fY=", + "dev": true + }, + "orchestrator": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", + "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "dev": true, + "requires": { + "end-of-stream": "0.1.5", + "sequencify": "0.0.7", + "stream-consume": "0.1.1" + } + }, + "ordered-read-streams": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", + "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "param-case": { + "version": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz" + } + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "requires": { + "is-absolute": "1.0.0", + "map-cache": "0.2.2", + "path-root": "0.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parserlib": { + "version": "https://registry.npmjs.org/parserlib/-/parserlib-1.1.1.tgz", + "integrity": "sha1-pkz6ckBiQ0/fw1HJpOwtkrlMBvQ=", + "dev": true + }, + "pascal-case": { + "version": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=", + "dev": true, + "requires": { + "camel-case": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "upper-case-first": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-case": { + "version": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz" + } + }, + "path-is-absolute": { + "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "requires": { + "path-root-regex": "0.1.2" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true + }, + "pause-stream": { + "version": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dev": true, + "requires": { + "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + } + }, + "performance-now": { + "version": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "6.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz", + "integrity": "sha512-y/bKfbQz2Nn/QBC08bwvYUxEFOVGfPIUOTsJ2CK5inzlXW9SdYR1x4pEsG9blRAF/PX+wRNdOah+gx/hv4q7dw==", + "dev": true, + "requires": { + "chalk": "2.3.2", + "source-map": "0.6.1", + "supports-color": "5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "supports-color": "5.3.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "process-nextick-args": { + "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=", + "dev": true + }, + "promise": { + "version": "https://registry.npmjs.org/promise/-/promise-8.0.1.tgz", + "integrity": "sha1-5F1osAoXZHttpxG/he1u1HII9FA=", + "dev": true, + "requires": { + "asap": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" + } + }, + "punycode": { + "version": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=", + "dev": true + }, + "rcfinder": { + "version": "https://registry.npmjs.org/rcfinder/-/rcfinder-0.1.9.tgz", + "integrity": "sha1-8+gPOH3fmugK4wpBADKWQuroERU=", + "dev": true, + "requires": { + "lodash.clonedeep": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" + } + }, + "rcloader": { + "version": "https://registry.npmjs.org/rcloader/-/rcloader-0.2.2.tgz", + "integrity": "sha1-WNIpi0YtC5v9ITPSoex0+9cFxxc=", + "dev": true, + "requires": { + "lodash.assign": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "lodash.isobject": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "lodash.merge": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "rcfinder": "https://registry.npmjs.org/rcfinder/-/rcfinder-0.1.9.tgz" + } + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "1.5.0" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "safe-regex": "1.1.0" + } + }, + "relateurl": { + "version": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "replace-ext": { + "version": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "replacestream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", + "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "dev": true, + "requires": { + "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "readable-stream": "2.3.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "1.0.0", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "string_decoder": "1.1.1", + "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" + } + } + } + }, + "request": { + "version": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha1-ygtl2gLtYpNYh4COb1EDgQNOM1Y=", + "dev": true, + "requires": { + "aws-sign2": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "aws4": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "caseless": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "combined-stream": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "forever-agent": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "form-data": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "har-validator": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "hawk": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "http-signature": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "is-typedarray": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "isstream": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "json-stringify-safe": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "oauth-sign": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "performance-now": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "qs": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "stringstream": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "tough-cookie": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "tunnel-agent": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "uuid": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz" + } + }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "right-align": { + "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz" + } + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "dev": true, + "requires": { + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz" + } + }, + "safe-buffer": { + "version": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "0.1.15" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true + }, + "sentence-case": { + "version": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "upper-case-first": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz" + } + }, + "sequencify": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", + "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", + "dev": true + }, + "set-getter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", + "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", + "dev": true, + "requires": { + "to-object-path": "0.3.0" + } + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "split-string": "3.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "snake-case": { + "version": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz" + } + }, + "snapdragon": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", + "integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=", + "dev": true, + "requires": { + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "source-map-resolve": "0.5.1", + "use": "2.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "1.0.0", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "snapdragon-util": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "sntp": { + "version": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha1-LGzsFP7cIiJznK+bXD2F0cxaLMg=", + "dev": true, + "requires": { + "hoek": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz" + } + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", + "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", + "dev": true, + "requires": { + "atob": "2.0.3", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sparkles": { + "version": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", + "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=", + "dev": true + }, + "split": { + "version": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dev": true, + "requires": { + "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "bcrypt-pbkdf": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "dashdash": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "ecc-jsbn": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "getpass": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "0.2.5", + "object-copy": "0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "stream-combiner": { + "version": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dev": true, + "requires": { + "duplexer": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz" + } + }, + "stream-consume": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", + "dev": true + }, + "stream-to-array": { + "version": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz", + "integrity": "sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M=", + "dev": true, + "requires": { + "any-promise": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" + } + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "stringstream": { + "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + } + }, + "strip-bom": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", + "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", + "dev": true, + "requires": { + "first-chunk-stream": "1.0.0", + "is-utf8": "0.2.1" + } + }, + "strong-data-uri": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strong-data-uri/-/strong-data-uri-1.0.5.tgz", + "integrity": "sha512-1iRpXhQLMTVwYEoR3w4k2fDolmFjFxBrCY0foxLLZFja7sKwKCyw1U4MzPQIQ0SPnXLm8R6rykvEpsdBE9TGqw==", + "dev": true, + "requires": { + "truncate": "2.0.1" + } + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "1.0.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + } + }, + "swap-case": { + "version": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=", + "dev": true, + "requires": { + "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" + } + }, + "textextensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz", + "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==", + "dev": true + }, + "through": { + "version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", + "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + }, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", + "integrity": "sha1-yUbD9H+n2Oq8C2FQ9KEvaaRXQHE=", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + } + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "dev": true, + "requires": { + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" + } + } + } + }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + }, + "time-stamp": { + "version": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "title-case": { + "version": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=", + "dev": true, + "requires": { + "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "2.0.2", + "extend-shallow": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + } + }, + "tough-cookie": { + "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", + "dev": true, + "requires": { + "punycode": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" + } + }, + "truncate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/truncate/-/truncate-2.0.1.tgz", + "integrity": "sha1-3RptFWMFFWY9hHX28k7fL4AOuxs=", + "dev": true + }, + "tryit": { + "version": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true + }, + "tunnel-agent": { + "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" + } + }, + "tweetnacl": { + "version": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", + "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=", + "dev": true, + "requires": { + "async": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "uglify-to-browserify": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + }, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, + "uglify-save-license": { + "version": "https://registry.npmjs.org/uglify-save-license/-/uglify-save-license-0.4.1.tgz", + "integrity": "sha1-lXJsF8xv0XHDYX479NjYKqjEzOE=", + "dev": true + }, + "uglify-to-browserify": { + "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "to-object-path": "0.3.0" + } + } + } + }, + "unique-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", + "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "0.3.1", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "upper-case": { + "version": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "upper-case-first": { + "version": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=", + "dev": true, + "requires": { + "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", + "integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=", + "dev": true, + "requires": { + "define-property": "0.2.5", + "isobject": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "lazy-cache": "2.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true + }, + "util-deprecate": { + "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha1-EsUou51Y0LkmXZovbw/ovhf/HxQ=", + "dev": true + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "dev": true, + "requires": { + "user-home": "1.1.1" + } + }, + "verror": { + "version": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" + } + }, + "vinyl": { + "version": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "dev": true, + "requires": { + "clone": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", + "clone-stats": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "replace-ext": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz" + } + }, + "vinyl-fs": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", + "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", + "dev": true, + "requires": { + "defaults": "1.0.3", + "glob-stream": "3.1.18", + "glob-watcher": "0.0.6", + "graceful-fs": "3.0.11", + "mkdirp": "0.5.1", + "strip-bom": "1.0.0", + "through2": "0.6.5", + "vinyl": "0.4.6" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + } + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "dev": true, + "requires": { + "clone": "0.2.0", + "clone-stats": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz" + } + } + } + }, + "vinyl-sourcemaps-apply": { + "version": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "dev": true, + "requires": { + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + } + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "window-size": { + "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "wrappy": { + "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml-char-classes": { + "version": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", + "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=", + "dev": true + }, + "xtend": { + "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yargs": { + "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "cliui": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "window-size": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" + } + } + } +} diff --git a/code/package.json b/code/package.json index 28b6f3a6..b44335c6 100644 --- a/code/package.json +++ b/code/package.json @@ -1,22 +1,23 @@ { "name": "esp8266-filesystem-builder", - "version": "0.2.0", + "version": "0.2.1", "description": "Gulp based build system for ESP8266 file system files", "main": "gulpfile.js", "author": "Xose Pérez ", "license": "GPL-3.0", "devDependencies": { "del": "^2.2.1", + "fancy-log": "^1.3.2", "gulp": "^3.9.1", "gulp-base64-favicon": "^1.0.2", - "gulp-clean-css": "^3.4.2", + "gulp-crass": "^0.2.2", "gulp-css-base64": "^1.3.4", + "gulp-csslint": "^1.0.0", "gulp-gzip": "^1.4.0", "gulp-htmllint": "0.0.14", "gulp-htmlmin": "^2.0.0", "gulp-inline": "^0.1.1", - "gulp-uglify": "^1.5.3", - "gulp-util": "^3.0.8" - }, - "dependencies": {} + "gulp-replace": "^1.0.0", + "gulp-uglify": "^1.5.3" + } } diff --git a/code/platformio.ini b/code/platformio.ini index be19f30d..eae6057b 100644 --- a/code/platformio.ini +++ b/code/platformio.ini @@ -4,39 +4,174 @@ src_dir = espurna data_dir = espurna/data [common] -platform = espressif8266 -#platform = espressif8266_stage -build_flags = -g -DMQTT_MAX_PACKET_SIZE=400 ${env.ESPURNA_FLAGS} +# ------------------------------------------------------------------------------ +# PLATFORM: +# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266 +# We use platformIO 1.5.0 as default +# +# platformIO 1.5.0 = arduino core 2.3.0 +# platformIO 1.6.0 = arduino core 2.4.0 +# platformIO 1.7.0 = arduino core 2.4.1 +# ------------------------------------------------------------------------------ +platform_150 = espressif8266@1.5.0 +platform_160 = espressif8266@1.6.0 +platform_170 = espressif8266@1.7.0 +platform = ${common.platform_150} + +# ------------------------------------------------------------------------------ +# FLAGS: DEBUG +# +# ------------------------------------------------------------------------------ debug_flags = -DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM -build_flags_512k = ${common.build_flags} -Wl,-Tesp8266.flash.512k0.ld -build_flags_1m = ${common.build_flags} -Wl,-Tesp8266.flash.1m0.ld + +# ------------------------------------------------------------------------------ +# FLAGS: build flags +# build flags for 512k/1m ESP's are different because we use Linker Scripts to adjust flash split +# 512 KB = 487 KB sketch, 20 KB eeprom +# 1 MB = 999 KB sketch, 20 KB eeprom +# +# Available lwIP variants (macros): +# -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH v1.4 Higher Bandwidth (default) +# -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY v2 Lower Memory +# -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_512k = ${common.build_flags} -Wl,-Teagle.flash.512k0m1s.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_4m3m = ${common.build_flags} -Wl,-Teagle.flash.4m3m4s.ld + +# ------------------------------------------------------------------------------ +# GLOBALS: +# ------------------------------------------------------------------------------ +# IP address when using OTA +upload_port = "192.168.4.1" +upload_flags = --auth=fibonacci --port 8266 +#upload_port = "${env.ESPURNA_IP}" +#upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 + +# ------------------------------------------------------------------------------ +# LIBRARIES: required dependencies +# Please note that we don't always use the latest version of a library. +# ------------------------------------------------------------------------------ lib_deps = - https://github.com/xoseperez/Time ArduinoJson - https://github.com/me-no-dev/ESPAsyncTCP#a57560d - https://github.com/me-no-dev/ESPAsyncWebServer#313f337 https://github.com/marvinroger/async-mqtt-client#v0.8.1 - PubSubClient - Embedis - NtpClientLib - OneWire Brzo I2C - https://github.com/krosk93/espsoftwareserial#a770677 - SparkFun BME280 - PMS Library - FastLED - https://bitbucket.org/xoseperez/justwifi.git#1.1.4 - https://bitbucket.org/xoseperez/hlw8012.git#1.1.0 - https://bitbucket.org/xoseperez/fauxmoesp.git#2.3.0 - https://bitbucket.org/xoseperez/nofuss.git#0.2.5 https://bitbucket.org/xoseperez/debounceevent.git#2.0.1 - https://github.com/xoseperez/my92xx#3.0.0 - https://github.com/xoseperez/RemoteSwitch-arduino-library.git + https://github.com/xoseperez/eeprom_rotate#0.9.1 + Embedis + https://github.com/plerup/espsoftwareserial#3.4.1 + https://github.com/me-no-dev/ESPAsyncTCP#55cd520 + https://github.com/me-no-dev/ESPAsyncWebServer#05306e4 + FastLED + https://bitbucket.org/xoseperez/fauxmoesp.git#2.4.2 + https://github.com/xoseperez/hlw8012.git#1.1.0 https://github.com/markszabo/IRremoteESP8266#v2.2.0 + https://github.com/xoseperez/justwifi.git#2.0.0 + https://github.com/madpilot/mDNSResolver#4cfcda1 + https://github.com/xoseperez/my92xx#3.0.1 + https://bitbucket.org/xoseperez/nofuss.git#0.2.5 + https://github.com/xoseperez/NtpClient.git#0016a59 + OneWire + PZEM004T + PubSubClient + rc-switch + https://github.com/xoseperez/Time lib_ignore = -#extra_scripts = post:core_version.py -extra_scripts = +extra_scripts = extra_scripts.py + +# ------------------------------------------------------------------------------ +# ESPURNA CORE BUILDS +# ------------------------------------------------------------------------------ + +[env:espurna-core-1MB] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DESPURNA_CORE +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:espurna-core-4MB] +platform = ${common.platform} +framework = arduino +board = d1_mini +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DESPURNA_CORE +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +# ------------------------------------------------------------------------------ +# GENERIC OTA ENVIRONMENTS +# ------------------------------------------------------------------------------ + +[env:esp8266-1m-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -D${env.ESPURNA_BOARD} +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:esp8266-4m-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -D${env.ESPURNA_BOARD} +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +# ------------------------------------------------------------------------------ +# SPECIAL BUILDS - DO. NOT. USE. ever --- +# ------------------------------------------------------------------------------ +[env:travis01] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DTRAVIS01 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} +[env:travis02] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DTRAVIS02 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:travis03] +platform = espressif8266@1.6.0 +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DTRAVIS03 -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +# ------------------------------------------------------------------------------ +# DEVELOPMENT BOARDS # ------------------------------------------------------------------------------ [env:wemos-d1mini-relayshield] @@ -45,20 +180,21 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH +build_flags = ${common.build_flags_4m1m} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 extra_scripts = ${common.extra_scripts} [env:wemos-d1mini-relayshield-ssl] -platform = espressif8266_stage +platform = espressif8266@1.6.0 framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1 +build_flags = ${common.build_flags_4m1m} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1 upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:wemos-d1mini-relayshield-ota] platform = ${common.platform} @@ -66,10 +202,11 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH +build_flags = ${common.build_flags_4m1m} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +extra_scripts = ${common.extra_scripts} [env:nodemcu-lolin] platform = ${common.platform} @@ -77,19 +214,21 @@ framework = arduino board = nodemcuv2 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH +build_flags = ${common.build_flags_4m1m} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:nodemcu-lolin-ssl] -platform = espressif8266_stage +platform = espressif8266@1.6.0 framework = arduino board = nodemcuv2 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1 +build_flags = ${common.build_flags_4m1m} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1 upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:nodemcu-lolin-ota] platform = ${common.platform} @@ -97,12 +236,15 @@ framework = arduino board = nodemcuv2 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH +build_flags = ${common.build_flags_4m1m} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} +# ------------------------------------------------------------------------------ +# SPECIFIC BOARDS # ------------------------------------------------------------------------------ [env:tinkerman-espurna-h06] @@ -111,8 +253,9 @@ framework = arduino board = esp12e lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H06 -monitor_baud = 115200 +build_flags = ${common.build_flags_4m1m} -DTINKERMAN_ESPURNA_H06 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:tinkerman-espurna-h06-ota] platform = ${common.platform} @@ -120,11 +263,12 @@ framework = arduino board = esp12e lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H06 +build_flags = ${common.build_flags_4m1m} -DTINKERMAN_ESPURNA_H06 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:tinkerman-espurna-h08] platform = ${common.platform} @@ -132,8 +276,9 @@ framework = arduino board = esp12e lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H08 -monitor_baud = 115200 +build_flags = ${common.build_flags_4m1m} -DTINKERMAN_ESPURNA_H08 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:tinkerman-espurna-h08-ota] platform = ${common.platform} @@ -141,11 +286,32 @@ framework = arduino board = esp12e lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H08 +build_flags = ${common.build_flags_4m1m} -DTINKERMAN_ESPURNA_H08 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:tinkerman-espurna-switch] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DTINKERMAN_ESPURNA_SWITCH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:wemos-d1-tarpunashield] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DWEMOS_D1_TARPUNA_SHIELD +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} # ------------------------------------------------------------------------------ @@ -153,375 +319,458 @@ monitor_baud = 115200 platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_BASIC +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-basic-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_BASIC upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-basic-dht] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC -DDHT_SUPPORT=1 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_BASIC -DDHT_SUPPORT=1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-basic-dht-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC -DDHT_SUPPORT=1 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_BASIC -DDHT_SUPPORT=1 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-basic-dallas] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC -DDALLAS_SUPPORT=1 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_BASIC -DDALLAS_SUPPORT=1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-rf] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_RF -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_RF +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-rf-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_RF +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_RF upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-th] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TH -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_TH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-th-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TH +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_TH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-pow] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_POW -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_POW +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-pow-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_POW +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_POW upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:itead-sonoff-pow-r2] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_POW_R2 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:itead-sonoff-pow-r2-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_POW_R2 +upload_speed = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-dual] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_DUAL +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-dual-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_DUAL upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-dual-r2] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL_R2 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_DUAL_R2 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-dual-ota-r2] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL_R2 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_DUAL_R2 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-4ch] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_4CH -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_4CH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-4ch-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_4CH +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_4CH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-4ch-pro] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_4CH_PRO -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_4CH_PRO +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-4ch-pro-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_4CH_PRO +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_4CH_PRO upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-touch] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TOUCH -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_TOUCH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-touch-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TOUCH +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_TOUCH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-b1] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_B1 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_B1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-b1-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_B1 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_B1 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-t1-1ch] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_1CH -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_T1_1CH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-t1-1ch-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_1CH +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_T1_1CH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-t1-2ch] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_2CH -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_T1_2CH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-t1-2ch-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_2CH +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_T1_2CH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-t1-3ch] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_3CH -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_T1_3CH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-t1-3ch-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_3CH +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_T1_3CH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-led] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_LED -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_LED +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-led-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_LED +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_LED upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-rfbridge] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_RFBRIDGE -monitor_baud = 19200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_RFBRIDGE +monitor_speed = 19200 +extra_scripts = ${common.extra_scripts} [env:itead-sonoff-rfbridge-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_RFBRIDGE +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_RFBRIDGE upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=Algernon1 --port 8266 -monitor_baud = 19200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 19200 +extra_scripts = ${common.extra_scripts} + +[env:itead-sonoff-rfbridge-direct] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_RFBRIDGE -DRFB_DIRECT +monitor_speed = 19200 +extra_scripts = ${common.extra_scripts} + +[env:itead-sonoff-rfbridge-direct-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_RFBRIDGE -DRFB_DIRECT +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +monitor_speed = 19200 +extra_scripts = ${common.extra_scripts} # ------------------------------------------------------------------------------ @@ -529,160 +778,245 @@ monitor_baud = 19200 platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SLAMPHER -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SLAMPHER +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-slampher-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_SLAMPHER +build_flags = ${common.build_flags_1m0m} -DITEAD_SLAMPHER upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-s20] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_S20 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_S20 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-s20-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_S20 +build_flags = ${common.build_flags_1m0m} -DITEAD_S20 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-1ch-inching] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_1CH_INCHING -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_1CH_INCHING +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-1ch-inching-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_1CH_INCHING +build_flags = ${common.build_flags_1m0m} -DITEAD_1CH_INCHING upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-motor] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_MOTOR -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_MOTOR +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-motor-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_MOTOR +build_flags = ${common.build_flags_1m0m} -DITEAD_MOTOR upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 - -# ------------------------------------------------------------------------------ +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -[env:electrodragon-wifi-iot] +[env:itead-sonoff-sv] platform = ${common.platform} framework = arduino -board = esp12e +board = esp01_1m +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DELECTRODRAGON_WIFI_IOT -DDHT_SUPPORT=1 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_SV +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -[env:electrodragon-wifi-iot-ota] +[env:itead-sonoff-sv-ota] platform = ${common.platform} framework = arduino -board = esp12e +board = esp01_1m +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DELECTRODRAGON_WIFI_IOT -DDHT_SUPPORT=1 -upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_SV +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -[env:workchoice-ecoplug] +[env:itead-sonoff-s31] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DWORKCHOICE_ECOPLUG -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_S31 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -[env:workchoice-ecoplug-ota] +[env:itead-sonoff-s31-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DWORKCHOICE_ECOPLUG -upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_SONOFF_S31 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -[env:jangoe-wifi-relay] +# ------------------------------------------------------------------------------ + +[env:electrodragon-wifi-iot] platform = ${common.platform} framework = arduino board = esp12e lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DJANGOE_WIFI_RELAY_NC -monitor_baud = 115200 +build_flags = ${common.build_flags_4m1m} -DELECTRODRAGON_WIFI_IOT -DDHT_SUPPORT=1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -[env:jangoe-wifi-relay-ota] +[env:electrodragon-wifi-iot-ota] platform = ${common.platform} framework = arduino board = esp12e lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DJANGOE_WIFI_RELAY_NC +build_flags = ${common.build_flags_4m1m} -DELECTRODRAGON_WIFI_IOT -DDHT_SUPPORT=1 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:workchoice-ecoplug] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DWORKCHOICE_ECOPLUG +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:workchoice-ecoplug-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DWORKCHOICE_ECOPLUG +upload_speed = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:jangoe-wifi-relay-nc] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DJANGOE_WIFI_RELAY_NC +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:jangoe-wifi-relay-nc-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DJANGOE_WIFI_RELAY_NC +upload_speed = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:jangoe-wifi-relay-no] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DJANGOE_WIFI_RELAY_NO +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:jangoe-wifi-relay-no-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DJANGOE_WIFI_RELAY_NO +upload_speed = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:openenergymonitor-mqtt-relay] platform = ${common.platform} @@ -690,8 +1024,9 @@ framework = arduino board = esp_wroom_02 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DOPENENERGYMONITOR_MQTT_RELAY -DDALLAS_SUPPORT=1 -monitor_baud = 115200 +build_flags = ${common.build_flags_4m1m} -DOPENENERGYMONITOR_MQTT_RELAY -DDALLAS_SUPPORT=1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:openenergymonitor-mqtt-relay-ota] platform = ${common.platform} @@ -699,11 +1034,12 @@ framework = arduino board = esp_wroom_02 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DOPENENERGYMONITOR_MQTT_RELAY -DDALLAS_SUPPORT=1 +build_flags = ${common.build_flags_4m1m} -DOPENENERGYMONITOR_MQTT_RELAY -DDALLAS_SUPPORT=1 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:jorgegarcia-wifi-relays] platform = ${common.platform} @@ -711,8 +1047,9 @@ framework = arduino board = esp01_1m lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DJORGEGARCIA_WIFI_RELAYS -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DJORGEGARCIA_WIFI_RELAYS +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:jorgegarcia-wifi-relays-ota] platform = ${common.platform} @@ -720,286 +1057,336 @@ framework = arduino board = esp01_1m lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DJORGEGARCIA_WIFI_RELAYS +build_flags = ${common.build_flags_1m0m} -DJORGEGARCIA_WIFI_RELAYS upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:aithinker-ai-light] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DAITHINKER_AI_LIGHT -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DAITHINKER_AI_LIGHT +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:aithinker-ai-light-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DAITHINKER_AI_LIGHT +build_flags = ${common.build_flags_1m0m} -DAITHINKER_AI_LIGHT upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:magichome-led-controller] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DMAGICHOME_LED_CONTROLLER +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:magichome-led-controller-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER +build_flags = ${common.build_flags_1m0m} -DMAGICHOME_LED_CONTROLLER upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:magichome-led-controller-20] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER_20 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DMAGICHOME_LED_CONTROLLER_20 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:magichome-led-controller-20-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER_20 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DMAGICHOME_LED_CONTROLLER_20 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:huacanxing-h801] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DHUACANXING_H801 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DHUACANXING_H801 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:huacanxing-h801-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DHUACANXING_H801 +build_flags = ${common.build_flags_1m0m} -DHUACANXING_H801 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:huacanxing-h802] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DHUACANXING_H802 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DHUACANXING_H802 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:huacanxing-h802-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DHUACANXING_H802 +build_flags = ${common.build_flags_1m0m} -DHUACANXING_H802 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-al-lc01] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC01 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC01 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-al-lc01-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC01 +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC01 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:arilux-al-lc02] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC02 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:arilux-al-lc02-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC02 +upload_speed = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-al-lc06] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC06 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC06 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-al-lc06-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC06 +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC06 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-al-lc11] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC11 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC11 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-al-lc11-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC11 +build_flags = ${common.build_flags_1m0m} -DARILUX_AL_LC11 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-e27] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_E27 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DARILUX_E27 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:arilux-e27-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_E27 +build_flags = ${common.build_flags_1m0m} -DARILUX_E27 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-bnsz01] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_BNSZ01 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DITEAD_BNSZ01 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:itead-bnsz01-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DITEAD_BNSZ01 +build_flags = ${common.build_flags_1m0m} -DITEAD_BNSZ01 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:wion-50055] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DWION_50055 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DWION_50055 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:wion-50055-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DWION_50055 +build_flags = ${common.build_flags_1m0m} -DWION_50055 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:exs-wifi-relay-v31] platform = ${common.platform} framework = arduino board = esp07 -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DEXS_WIFI_RELAY_V31 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DEXS_WIFI_RELAY_V31 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:exs-wifi-relay-v31-ota] platform = ${common.platform} framework = arduino board = esp07 -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DEXS_WIFI_RELAY_V31 +build_flags = ${common.build_flags_1m0m} -DEXS_WIFI_RELAY_V31 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:wemos-v9261f] platform = ${common.platform} @@ -1007,9 +1394,10 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DGENERIC_V9261F +build_flags = ${common.build_flags_4m1m} -DGENERIC_V9261F upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:wemos-v9261f-ota] platform = ${common.platform} @@ -1017,34 +1405,37 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DGENERIC_V9261F +build_flags = ${common.build_flags_4m1m} -DGENERIC_V9261F upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:esp01-v9261f] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DGENERIC_V9261F -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DGENERIC_V9261F +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:esp01-v9261f-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DGENERIC_V9261F +build_flags = ${common.build_flags_1m0m} -DGENERIC_V9261F upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:wemos-ech1560] platform = ${common.platform} @@ -1052,9 +1443,10 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DGENERIC_ECH1560 +build_flags = ${common.build_flags_4m1m} -DGENERIC_ECH1560 upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:wemos-ech1560-ota] platform = ${common.platform} @@ -1062,34 +1454,37 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DGENERIC_ECH1560 +build_flags = ${common.build_flags_4m1m} -DGENERIC_ECH1560 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:esp01-ech1560] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DGENERIC_ECH1560 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DGENERIC_ECH1560 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:esp01-ech1560-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DGENERIC_ECH1560 +build_flags = ${common.build_flags_1m0m} -DGENERIC_ECH1560 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:mancavemade-esplive] platform = ${common.platform} @@ -1097,9 +1492,10 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DMANCAVEMADE_ESPLIVE +build_flags = ${common.build_flags_4m1m} -DMANCAVEMADE_ESPLIVE upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:mancavemade-esplive-ota] platform = ${common.platform} @@ -1107,103 +1503,137 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DMANCAVEMADE_ESPLIVE +build_flags = ${common.build_flags_4m1m} -DMANCAVEMADE_ESPLIVE upload_speed = 460800 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:intermittech-quinled] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DINTERMITTECH_QUINLED -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DINTERMITTECH_QUINLED +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:intermittech-quinled-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DINTERMITTECH_QUINLED +build_flags = ${common.build_flags_1m0m} -DINTERMITTECH_QUINLED upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:xenon-sm-pw702u] platform = ${common.platform} framework = arduino board = esp12e -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DXENON_SM_PW702U -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DXENON_SM_PW702U +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:xenon-sm-pw702u-ota] platform = ${common.platform} framework = arduino board = esp12e -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DXENON_SM_PW702U +build_flags = ${common.build_flags_1m0m} -DXENON_SM_PW702U upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:authometion-lyt8266] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DAUTHOMETION_LYT8266 -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DAUTHOMETION_LYT8266 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:authometion-lyt8266-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DAUTHOMETION_LYT8266 +build_flags = ${common.build_flags_1m0m} -DAUTHOMETION_LYT8266 upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:kmc-70011] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DKMC_70011 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:kmc-70011-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DKMC_70011 +upload_speed = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:yjzk-switch-2ch] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DYJZK_SWITCH_2CH -monitor_baud = 115200 +build_flags = ${common.build_flags_1m0m} -DYJZK_SWITCH_2CH +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:yjzk-switch-2ch-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -DYJZK_SWITCH_2CH +build_flags = ${common.build_flags_1m0m} -DYJZK_SWITCH_2CH upload_speed = 115200 -upload_port = "192.168.4.1" -upload_flags = --auth=fibonacci --port 8266 -monitor_baud = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} [env:generic-8ch] platform = ${common.platform} @@ -1211,34 +1641,601 @@ framework = arduino board = d1_mini lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DGENERIC_8CH +build_flags = ${common.build_flags_4m1m} -DGENERIC_8CH upload_speed = 460800 -monitor_baud = 115200 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -# ------------------------------------------------------------------------------ -# GENERIC OTA ENVIRONMENTS -# ------------------------------------------------------------------------------ +[env:gizwits-witty-cloud] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DGIZWITS_WITTY_CLOUD +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} -[env:esp8266-1m-ota] +[env:gizwits-witty-cloud-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DGIZWITS_WITTY_CLOUD +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:euromate-wifi-stecker-shuko] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DEUROMATE_WIFI_STECKER_SCHUKO +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:euromate-wifi-stecker-shuko-ota] platform = ${common.platform} framework = arduino board = esp01_1m -board_flash_mode = dout +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags_1m} -D${env.ESPURNA_BOARD} +build_flags = ${common.build_flags_4m1m} -DEUROMATE_WIFI_STECKER_SCHUKO upload_speed = 115200 upload_port = "${env.ESPURNA_IP}" upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} -[env:esp8266-4m-ota] +[env:tonbux-powerstrip02] platform = ${common.platform} framework = arduino -board = esp12e -board_flash_mode = dout +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DTONBUX_POWERSTRIP02 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:tonbux-powerstrip02-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DTONBUX_POWERSTRIP02 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:lingan-swa1] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DLINGAN_SWA1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:lingan-swa1-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -D${env.ESPURNA_BOARD} +build_flags = ${common.build_flags_4m1m} -DLINGAN_SWA1 upload_speed = 115200 upload_port = "${env.ESPURNA_IP}" upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:stm-relay] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DSTM_RELAY +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:stm-relay-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DSTM_RELAY +upload_speed = 115200 +upload_port = ${common.upload_port} +upload_flags = ${common.upload_flags} +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:heygo-hy02] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DHEYGO_HY02 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:heygo-hy02-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DHEYGO_HY02 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:maxcio-wus002s] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DMAXCIO_WUS002S +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:maxcio-wus002s-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DMAXCIO_WUS002S +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:yidian-xsssa05] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DYIDIAN_XSSSA05 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:yidian-xsssa05-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DYIDIAN_XSSSA05 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:tonbux-xsssa06] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DTONBUX_XSSSA06 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:tonbux-xsssa06-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DTONBUX_XSSSA06 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:green-esp8266relay] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DGREEN_ESP8266RELAY +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:green-esp8266relay-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DGREEN_ESP8266RELAY +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:ike-espike] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DIKE_ESPIKE +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:ike-espike-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DIKE_ESPIKE +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:arniex-swifitch] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DARNIEX_SWIFITCH +extra_scripts = ${common.extra_scripts} +monitor_speed = 115200 + +[env:arniex-swifitch-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DARNIEX_SWIFITCH +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:zhilde-eu44-w] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DZHILDE_EU44_W +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:zhilde-eu44-w-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DZHILDE_EU44_W +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:luani-hvio] +platform = ${common.platform} +framework = arduino +board = esp07 +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DLUANI_HVIO +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:luani-hvio-ota] +platform = ${common.platform} +framework = arduino +board = esp07 +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DZLUANI_HVIO +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:neo-coolcam-power-plug-wifi] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DNEO_COOLCAM_POWER_PLUG_WIFI +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:neo-coolcam-power-plug-wifi-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DNEO_COOLCAM_POWER_PLUG_WIFI +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:estink-wifi-power-strip] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DESTINK_WIFI_POWER_STRIP +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:estink-wifi-power-strip-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_4m1m} -DESTINK_WIFI_POWER_STRIP +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +# ------------------------------------------------------------------------------ +# GENERIC OTA ENVIRONMENTS +# ------------------------------------------------------------------------------ + +[env:generic-esp01s-relay-40] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_RELAY_V40 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:generic-esp01s-relay-40-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_RELAY_V40 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:generic-esp01s-rgbled-10] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_RGBLED_V10 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:generic-esp01s-rgbled-10-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_RGBLED_V10 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:generic-esp01s-dht11-10] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_DHT11_V10 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:generic-esp01s-dht11-10-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_DHT11_V10 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:generic-esp01s-ds18b20-10] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_DS18B20_V10 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:generic-esp01s-ds18b20-10-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DGENERIC_ESP01S_DS18B20_V10 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:heltec-touch-relay] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DHELTEC_TOUCHRELAY +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:heltec-touch-relay-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DHELTEC_TOUCHRELAY +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:allnet-4duino-iot-wlan-relais] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DALLNET_4DUINO_IOT_WLAN_RELAIS +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:allnet-4duino-iot-wlan-relais-ota] +platform = ${common.platform} +framework = arduino +board = esp12e +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DALLNET_4DUINO_IOT_WLAN_RELAIS +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:tonbux-mosquito-killer] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DTONBUX_MOSQUITO_KILLER +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:tonbux-mosquito-killer-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DTONBUX_MOSQUITO_KILLER +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:pilotak-esp-din-v1] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DPILOTAK_ESP_DIN_V1 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} + +[env:pilotak-esp-din-v1-ota] +platform = ${common.platform} +framework = arduino +board = esp01_1m +board_build.flash_mode = dout +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DPILOTAK_ESP_DIN_V1 +upload_speed = 115200 +upload_port = "${env.ESPURNA_IP}" +upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 +extra_scripts = ${common.extra_scripts} + +[env:nodemcu-geiger] +platform = ${common.platform} +framework = arduino +board = nodemcu +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +build_flags = ${common.build_flags_1m0m} -DNODEMCU_BASIC -DNOWSAUTH -DGEIGER_SUPPORT=1 -DEVENTS_SUPPORT=0 -DINFLUXDB_SUPPORT=1 -DALEXA_SUPPORT=0 -DALEXA_ENABLED=0 +upload_speed = 460800 +monitor_speed = 115200 +extra_scripts = ${common.extra_scripts} diff --git a/code/requirements.txt b/code/requirements.txt new file mode 100644 index 00000000..a358f38e --- /dev/null +++ b/code/requirements.txt @@ -0,0 +1,6 @@ +enum-compat==0.0.2 +netifaces==0.10.6 +ordereddict==1.1 +six==1.11.0 +sortedcontainers==1.5.9 +zeroconf==0.19.1 diff --git a/code/symbols.sh b/code/symbols.sh new file mode 100755 index 00000000..4156a116 --- /dev/null +++ b/code/symbols.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# ------------------------------------------------------------------------------ +# CONFIGURATION +# ------------------------------------------------------------------------------ + +ENVIRONMENT="wemos-d1mini-relayshield" +READELF="xtensa-lx106-elf-readelf" +NUMBER=20 + +# ------------------------------------------------------------------------------ +# END CONFIGURATION - DO NOT EDIT FURTHER +# ------------------------------------------------------------------------------ + +# remove default trace file +rm -rf $FILE + +function help { + echo + echo "Syntax: $0 [-e ] [-n ]" + echo +} + +# get environment from command line +while [[ $# -gt 1 ]]; do + + key="$1" + + case $key in + -e) + ENVIRONMENT="$2" + shift + ;; + -n) + NUMBER="$2" + shift + ;; + esac + + shift # past argument or value + +done + +# check environment folder +if [ $ENVIRONMENT == "" ]; then + echo "No environment defined" + help + exit 1 +fi +ELF=.pioenvs/$ENVIRONMENT/firmware.elf +if [ ! -f $ELF ]; then + echo "Could not find ELF file for the selected environment: $ELF" + exit 2 +fi + +$READELF -s $ELF | head -3 | tail -1 +$READELF -s $ELF | sort -r -k3 -n | head -$NUMBER diff --git a/images/devices/aithinker-ai-light.jpg b/images/devices/aithinker-ai-light.jpg index 5fc1076e..535c61de 100644 Binary files a/images/devices/aithinker-ai-light.jpg and b/images/devices/aithinker-ai-light.jpg differ diff --git a/images/devices/arilux-al-lc01.jpg b/images/devices/arilux-al-lc01.jpg new file mode 100644 index 00000000..de036d83 Binary files /dev/null and b/images/devices/arilux-al-lc01.jpg differ diff --git a/images/devices/arilux-al-lc02.jpg b/images/devices/arilux-al-lc02.jpg new file mode 100644 index 00000000..f2058ff1 Binary files /dev/null and b/images/devices/arilux-al-lc02.jpg differ diff --git a/images/devices/arilux-al-lc06.jpg b/images/devices/arilux-al-lc06.jpg new file mode 100644 index 00000000..df173391 Binary files /dev/null and b/images/devices/arilux-al-lc06.jpg differ diff --git a/images/devices/arilux-al-lc11.jpg b/images/devices/arilux-al-lc11.jpg new file mode 100644 index 00000000..b9300417 Binary files /dev/null and b/images/devices/arilux-al-lc11.jpg differ diff --git a/images/devices/arilux-e27.jpg b/images/devices/arilux-e27.jpg new file mode 100644 index 00000000..3dbe44ab Binary files /dev/null and b/images/devices/arilux-e27.jpg differ diff --git a/images/devices/arniex-swifitch.jpg b/images/devices/arniex-swifitch.jpg new file mode 100644 index 00000000..373036ff Binary files /dev/null and b/images/devices/arniex-swifitch.jpg differ diff --git a/images/devices/authometion-lyt8266.jpg b/images/devices/authometion-lyt8266.jpg new file mode 100644 index 00000000..12f37544 Binary files /dev/null and b/images/devices/authometion-lyt8266.jpg differ diff --git a/images/devices/electrodragon-wifi-iot.jpg b/images/devices/electrodragon-wifi-iot.jpg index 8a6ac83b..4d567edd 100644 Binary files a/images/devices/electrodragon-wifi-iot.jpg and b/images/devices/electrodragon-wifi-iot.jpg differ diff --git a/images/devices/exs-wifi-relay-v31.jpg b/images/devices/exs-wifi-relay-v31.jpg index baefef2c..fda8d78c 100644 Binary files a/images/devices/exs-wifi-relay-v31.jpg and b/images/devices/exs-wifi-relay-v31.jpg differ diff --git a/images/devices/geiger_espurna_configuration.png b/images/devices/geiger_espurna_configuration.png new file mode 100644 index 00000000..1316084d Binary files /dev/null and b/images/devices/geiger_espurna_configuration.png differ diff --git a/images/devices/geiger_espurna_status.png b/images/devices/geiger_espurna_status.png new file mode 100644 index 00000000..26bd8185 Binary files /dev/null and b/images/devices/geiger_espurna_status.png differ diff --git a/images/devices/geiger_grafana_dashboard.png b/images/devices/geiger_grafana_dashboard.png new file mode 100644 index 00000000..d997f7a4 Binary files /dev/null and b/images/devices/geiger_grafana_dashboard.png differ diff --git a/images/devices/geiger_scope_following_pulses.png b/images/devices/geiger_scope_following_pulses.png new file mode 100755 index 00000000..63fd5b5a Binary files /dev/null and b/images/devices/geiger_scope_following_pulses.png differ diff --git a/images/devices/geiger_scope_single_pulse.png b/images/devices/geiger_scope_single_pulse.png new file mode 100755 index 00000000..d5d38782 Binary files /dev/null and b/images/devices/geiger_scope_single_pulse.png differ diff --git a/images/devices/geiger_wiring_diagram.png b/images/devices/geiger_wiring_diagram.png new file mode 100644 index 00000000..730a0845 Binary files /dev/null and b/images/devices/geiger_wiring_diagram.png differ diff --git a/images/devices/generic-dht11-10.jpg b/images/devices/generic-dht11-10.jpg new file mode 100644 index 00000000..65cf8e9a Binary files /dev/null and b/images/devices/generic-dht11-10.jpg differ diff --git a/images/devices/generic-ds18b20-10.jpg b/images/devices/generic-ds18b20-10.jpg new file mode 100644 index 00000000..16f94d7b Binary files /dev/null and b/images/devices/generic-ds18b20-10.jpg differ diff --git a/images/devices/generic-relay-40.jpg b/images/devices/generic-relay-40.jpg new file mode 100644 index 00000000..62a9144d Binary files /dev/null and b/images/devices/generic-relay-40.jpg differ diff --git a/images/devices/generic-rgbled-10.jpg b/images/devices/generic-rgbled-10.jpg new file mode 100644 index 00000000..24e8ad65 Binary files /dev/null and b/images/devices/generic-rgbled-10.jpg differ diff --git a/images/devices/generic-v9261f.jpg b/images/devices/generic-v9261f.jpg index 785a20e9..3fd12208 100644 Binary files a/images/devices/generic-v9261f.jpg and b/images/devices/generic-v9261f.jpg differ diff --git a/images/devices/heltec-touch-relay.jpg b/images/devices/heltec-touch-relay.jpg new file mode 100644 index 00000000..883e689f Binary files /dev/null and b/images/devices/heltec-touch-relay.jpg differ diff --git a/images/devices/heygo-hy02.jpg b/images/devices/heygo-hy02.jpg new file mode 100644 index 00000000..4bda4563 Binary files /dev/null and b/images/devices/heygo-hy02.jpg differ diff --git a/images/devices/huacanxing-h801.jpg b/images/devices/huacanxing-h801.jpg index da53c685..4f15cf5d 100644 Binary files a/images/devices/huacanxing-h801.jpg and b/images/devices/huacanxing-h801.jpg differ diff --git a/images/devices/ike-espike.jpg b/images/devices/ike-espike.jpg new file mode 100644 index 00000000..dbe7a577 Binary files /dev/null and b/images/devices/ike-espike.jpg differ diff --git a/images/devices/intermittech-quinled-2.6.jpg b/images/devices/intermittech-quinled-2.6.jpg new file mode 100644 index 00000000..6c491b93 Binary files /dev/null and b/images/devices/intermittech-quinled-2.6.jpg differ diff --git a/images/devices/itead-1ch-inching.jpg b/images/devices/itead-1ch-inching.jpg index fc227042..74920b7e 100644 Binary files a/images/devices/itead-1ch-inching.jpg and b/images/devices/itead-1ch-inching.jpg differ diff --git a/images/devices/itead-bn-sz01.jpg b/images/devices/itead-bn-sz01.jpg index 46e41873..1b1055f1 100644 Binary files a/images/devices/itead-bn-sz01.jpg and b/images/devices/itead-bn-sz01.jpg differ diff --git a/images/devices/itead-motor.jpg b/images/devices/itead-motor.jpg index 576de922..20bdc183 100644 Binary files a/images/devices/itead-motor.jpg and b/images/devices/itead-motor.jpg differ diff --git a/images/devices/itead-s20.jpg b/images/devices/itead-s20.jpg index 695850a5..9c620610 100644 Binary files a/images/devices/itead-s20.jpg and b/images/devices/itead-s20.jpg differ diff --git a/images/devices/itead-slampher.jpg b/images/devices/itead-slampher.jpg index d62d051f..1f406bbd 100644 Binary files a/images/devices/itead-slampher.jpg and b/images/devices/itead-slampher.jpg differ diff --git a/images/devices/itead-sonoff-4ch-pro.jpg b/images/devices/itead-sonoff-4ch-pro.jpg index 2e630d28..632ad0ff 100644 Binary files a/images/devices/itead-sonoff-4ch-pro.jpg and b/images/devices/itead-sonoff-4ch-pro.jpg differ diff --git a/images/devices/itead-sonoff-4ch.jpg b/images/devices/itead-sonoff-4ch.jpg index dea3fa45..ecb3477e 100644 Binary files a/images/devices/itead-sonoff-4ch.jpg and b/images/devices/itead-sonoff-4ch.jpg differ diff --git a/images/devices/itead-sonoff-b1.jpg b/images/devices/itead-sonoff-b1.jpg index 01f8100b..3b8b7315 100644 Binary files a/images/devices/itead-sonoff-b1.jpg and b/images/devices/itead-sonoff-b1.jpg differ diff --git a/images/devices/itead-sonoff-basic.jpg b/images/devices/itead-sonoff-basic.jpg index 26f034cb..9e7008d8 100644 Binary files a/images/devices/itead-sonoff-basic.jpg and b/images/devices/itead-sonoff-basic.jpg differ diff --git a/images/devices/itead-sonoff-dual.jpg b/images/devices/itead-sonoff-dual.jpg index 8dbc4a37..f9439cbf 100644 Binary files a/images/devices/itead-sonoff-dual.jpg and b/images/devices/itead-sonoff-dual.jpg differ diff --git a/images/devices/itead-sonoff-led.jpg b/images/devices/itead-sonoff-led.jpg index 33215c81..051d84cd 100644 Binary files a/images/devices/itead-sonoff-led.jpg and b/images/devices/itead-sonoff-led.jpg differ diff --git a/images/devices/itead-sonoff-pow.jpg b/images/devices/itead-sonoff-pow.jpg index c5458e25..fa5e61dd 100644 Binary files a/images/devices/itead-sonoff-pow.jpg and b/images/devices/itead-sonoff-pow.jpg differ diff --git a/images/devices/itead-sonoff-rf.jpg b/images/devices/itead-sonoff-rf.jpg index 70a14bb6..b86bd0fe 100644 Binary files a/images/devices/itead-sonoff-rf.jpg and b/images/devices/itead-sonoff-rf.jpg differ diff --git a/images/devices/itead-sonoff-rfbridge.jpg b/images/devices/itead-sonoff-rfbridge.jpg index fec73da1..e7c7b96b 100644 Binary files a/images/devices/itead-sonoff-rfbridge.jpg and b/images/devices/itead-sonoff-rfbridge.jpg differ diff --git a/images/devices/itead-sonoff-sv.jpg b/images/devices/itead-sonoff-sv.jpg index 86ea2c44..3b3514c1 100644 Binary files a/images/devices/itead-sonoff-sv.jpg and b/images/devices/itead-sonoff-sv.jpg differ diff --git a/images/devices/itead-sonoff-t1.jpg b/images/devices/itead-sonoff-t1.jpg index d01a6459..a081afbd 100644 Binary files a/images/devices/itead-sonoff-t1.jpg and b/images/devices/itead-sonoff-t1.jpg differ diff --git a/images/devices/itead-sonoff-th.jpg b/images/devices/itead-sonoff-th.jpg index a3e728d3..ee3c64ae 100644 Binary files a/images/devices/itead-sonoff-th.jpg and b/images/devices/itead-sonoff-th.jpg differ diff --git a/images/devices/itead-sonoff-touch.jpg b/images/devices/itead-sonoff-touch.jpg index 5156a2cb..f0e2f7ec 100644 Binary files a/images/devices/itead-sonoff-touch.jpg and b/images/devices/itead-sonoff-touch.jpg differ diff --git a/images/devices/jangoe-wifi-relay.jpg b/images/devices/jangoe-wifi-relay.jpg new file mode 100644 index 00000000..1d317921 Binary files /dev/null and b/images/devices/jangoe-wifi-relay.jpg differ diff --git a/images/devices/jangoe-wifi-relay.png b/images/devices/jangoe-wifi-relay.png deleted file mode 100644 index 271b6c7d..00000000 Binary files a/images/devices/jangoe-wifi-relay.png and /dev/null differ diff --git a/images/devices/jorgegarcia-wifi-relays.jpg b/images/devices/jorgegarcia-wifi-relays.jpg index a73a9069..7aa64595 100644 Binary files a/images/devices/jorgegarcia-wifi-relays.jpg and b/images/devices/jorgegarcia-wifi-relays.jpg differ diff --git a/images/devices/kmc-70011.jpg b/images/devices/kmc-70011.jpg new file mode 100644 index 00000000..ed07a7d0 Binary files /dev/null and b/images/devices/kmc-70011.jpg differ diff --git a/images/devices/lingan-swa1.jpg b/images/devices/lingan-swa1.jpg new file mode 100644 index 00000000..122a6967 Binary files /dev/null and b/images/devices/lingan-swa1.jpg differ diff --git a/images/devices/magichome-led-controller.jpg b/images/devices/magichome-led-controller.jpg index 52abd8d5..b8604977 100644 Binary files a/images/devices/magichome-led-controller.jpg and b/images/devices/magichome-led-controller.jpg differ diff --git a/images/devices/mancavemade-esp-live.jpg b/images/devices/mancavemade-esp-live.jpg new file mode 100644 index 00000000..bfe3b379 Binary files /dev/null and b/images/devices/mancavemade-esp-live.jpg differ diff --git a/images/devices/maxcio-w-us002s.jpg b/images/devices/maxcio-w-us002s.jpg new file mode 100644 index 00000000..a7974a55 Binary files /dev/null and b/images/devices/maxcio-w-us002s.jpg differ diff --git a/images/devices/nodemcu-lolin-v3.jpg b/images/devices/nodemcu-lolin-v3.jpg new file mode 100644 index 00000000..e9392742 Binary files /dev/null and b/images/devices/nodemcu-lolin-v3.jpg differ diff --git a/images/devices/openenergymonitor-mqtt-relay.jpg b/images/devices/openenergymonitor-mqtt-relay.jpg index e12231c9..5563f234 100644 Binary files a/images/devices/openenergymonitor-mqtt-relay.jpg and b/images/devices/openenergymonitor-mqtt-relay.jpg differ diff --git a/images/devices/schuko-wifi-plug.jpg b/images/devices/schuko-wifi-plug.jpg new file mode 100644 index 00000000..d4fef2be Binary files /dev/null and b/images/devices/schuko-wifi-plug.jpg differ diff --git a/images/devices/tinkerman-espurna-h.jpg b/images/devices/tinkerman-espurna-h.jpg index 9fd00ce7..29400268 100644 Binary files a/images/devices/tinkerman-espurna-h.jpg and b/images/devices/tinkerman-espurna-h.jpg differ diff --git a/images/devices/tonbux-mosquito-killer.jpg b/images/devices/tonbux-mosquito-killer.jpg new file mode 100644 index 00000000..dfed5f3c Binary files /dev/null and b/images/devices/tonbux-mosquito-killer.jpg differ diff --git a/images/devices/tonbux-powerstrip02.jpg b/images/devices/tonbux-powerstrip02.jpg new file mode 100644 index 00000000..070955e4 Binary files /dev/null and b/images/devices/tonbux-powerstrip02.jpg differ diff --git a/images/devices/tonbux-xs-ssa06.jpg b/images/devices/tonbux-xs-ssa06.jpg new file mode 100644 index 00000000..0aad3a96 Binary files /dev/null and b/images/devices/tonbux-xs-ssa06.jpg differ diff --git a/images/devices/wemos-d1-mini-relayshield.jpg b/images/devices/wemos-d1-mini-relayshield.jpg index 8ebb4b2d..a57c03bd 100644 Binary files a/images/devices/wemos-d1-mini-relayshield.jpg and b/images/devices/wemos-d1-mini-relayshield.jpg differ diff --git a/images/devices/wion-50055.jpg b/images/devices/wion-50055.jpg index 3d7c3774..1a78abd2 100644 Binary files a/images/devices/wion-50055.jpg and b/images/devices/wion-50055.jpg differ diff --git a/images/devices/witty-cloud.jpg b/images/devices/witty-cloud.jpg new file mode 100644 index 00000000..c343f940 Binary files /dev/null and b/images/devices/witty-cloud.jpg differ diff --git a/images/devices/workchoice-ecoplug.jpg b/images/devices/workchoice-ecoplug.jpg index 2605517b..49929ed8 100644 Binary files a/images/devices/workchoice-ecoplug.jpg and b/images/devices/workchoice-ecoplug.jpg differ diff --git a/images/devices/xenon-sm-pw702u.jpg b/images/devices/xenon-sm-pw702u.jpg new file mode 100644 index 00000000..93173820 Binary files /dev/null and b/images/devices/xenon-sm-pw702u.jpg differ diff --git a/images/devices/yidian-xs-ssa05.jpg b/images/devices/yidian-xs-ssa05.jpg new file mode 100644 index 00000000..1f36b69c Binary files /dev/null and b/images/devices/yidian-xs-ssa05.jpg differ diff --git a/images/devices/yjzk-2gang-switch.jpg b/images/devices/yjzk-2gang-switch.jpg new file mode 100644 index 00000000..81696468 Binary files /dev/null and b/images/devices/yjzk-2gang-switch.jpg differ diff --git a/images/icons/collaborate.png b/images/icons/collaborate.png new file mode 100644 index 00000000..b008582f Binary files /dev/null and b/images/icons/collaborate.png differ diff --git a/images/icons/documentation.png b/images/icons/documentation.png new file mode 100644 index 00000000..e302d5a6 Binary files /dev/null and b/images/icons/documentation.png differ diff --git a/images/icons/features.png b/images/icons/features.png new file mode 100644 index 00000000..fa63293c Binary files /dev/null and b/images/icons/features.png differ diff --git a/images/icons/hardware.png b/images/icons/hardware.png new file mode 100644 index 00000000..fb988277 Binary files /dev/null and b/images/icons/hardware.png differ diff --git a/pre-commit b/pre-commit new file mode 100755 index 00000000..acc37a69 --- /dev/null +++ b/pre-commit @@ -0,0 +1,123 @@ +#!/usr/bin/env python +""" + +Referencing current branch in github README.md [1] +This pre-commit hook [2] updates the README.md file's +Travis badge with the current branch. Based on [4]. + +[1] http://stackoverflow.com/questions/18673694/referencing-current-branch-in-github-readme-md +[2] http://www.git-scm.com/book/en/v2/Customizing-Git-Git-Hooks +[3] https://docs.travis-ci.com/user/status-images/ +[4] https://gist.github.com/dandye/dfe0870a6a1151c89ed9 + +Copy this file to .git/hooks/ + +""" + +import os +import sys +import re + +from subprocess import call, check_output +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + +from fileinput import FileInput +# https://github.com/python/cpython/commit/6cb7b659#diff-78790b53ff259619377058acd4f74672 +if sys.version_info[0] < 3: + class FileInputCtx(FileInput): + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + + FileInput = FileInputCtx + + +def run(cmd, cwd=None): + out = check_output(cmd, cwd=cwd) + out = out.decode("latin1").strip() + + return out + + +def parse_h_string(define, r_quotes=re.compile("\"(.*)\"")): + string = r_quotes.search(define).group(1) + return string + + +def git_parse_remote(cwd=None, remote="origin"): + remote_url = run([ + "git", "config", "--local", + "--get", "remote.{}.url".format(remote)], cwd) + + if remote_url.startswith("git"): + _, _, repo = remote_url.partition(":") + path = repo.replace(".git", "") + elif remote_url.startswith("https"): + parsed = urlparse(remote_url) + path = parsed.path[1:] + return path.split("/") + + +def git_branch(cwd=None): + return run(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd) + + +def espurna_get_version(base, version_h="code/espurna/config/version.h"): + version = "unknown" + + path = os.path.join(base, version_h) + with open(path, "r") as version_f: + for line in version_f: + if line.startswith("#define") and "APP_VERSION" in line: + version = parse_h_string(line) + break + + return version + +TEMPLATES = { + "![travis]": "[![travis](https://travis-ci.org/{USER}/{REPO}.svg?branch={BRANCH})]" \ + "(https://travis-ci.org/{USER}/{REPO})\n", + "![version]": "[![version](https://img.shields.io/badge/version-{VERSION}-brightgreen.svg)](CHANGELOG.md)\n", + "![branch]": "[![branch](https://img.shields.io/badge/branch-{BRANCH}-orange.svg)]" \ + "(https://github.org/{USER}/{REPO}/tree/{BRANCH}/)\n", + "![codacy]": "[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/{BRANCH}.svg)]" \ + "(https://www.codacy.com/app/{USER}/{REPO}/dashboard)\n" +} + +README = "README.md" + + +if __name__ == "__main__": + base = os.getcwd() + + user, repo = git_parse_remote() + fmt = { + "USER": user, + "REPO": repo, + "BRANCH": git_branch(), + "VERSION": espurna_get_version(base) + } + templates = [ + (k, tmpl.format(**fmt)) + for k, tmpl in TEMPLATES.items() + ] + + def fmt_line(line): + for match, tmpl in templates: + if match in line: + return tmpl + + return line + + path = os.path.join(base, README) + + with FileInput(path, inplace=True) as readme: + for line in readme: + sys.stdout.write(fmt_line(line)) + + sys.exit(call(["git", "add", README]))